My Marlin configs for Fabrikator Mini and CTC i3 Pro B
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.

udi_cdc.c 29KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155
  1. /**
  2. * \file
  3. *
  4. * \brief USB Device Communication Device Class (CDC) interface.
  5. *
  6. * Copyright (c) 2009-2016 Atmel Corporation. All rights reserved.
  7. *
  8. * \asf_license_start
  9. *
  10. * \page License
  11. *
  12. * Redistribution and use in source and binary forms, with or without
  13. * modification, are permitted provided that the following conditions are met:
  14. *
  15. * 1. Redistributions of source code must retain the above copyright notice,
  16. * this list of conditions and the following disclaimer.
  17. *
  18. * 2. Redistributions in binary form must reproduce the above copyright notice,
  19. * this list of conditions and the following disclaimer in the documentation
  20. * and/or other materials provided with the distribution.
  21. *
  22. * 3. The name of Atmel may not be used to endorse or promote products derived
  23. * from this software without specific prior written permission.
  24. *
  25. * 4. This software may only be redistributed and used in connection with an
  26. * Atmel microcontroller product.
  27. *
  28. * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
  29. * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
  30. * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
  31. * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
  32. * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  33. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  34. * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  35. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
  36. * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
  37. * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  38. * POSSIBILITY OF SUCH DAMAGE.
  39. *
  40. * \asf_license_stop
  41. *
  42. */
  43. /*
  44. * Support and FAQ: visit <a href="http://www.atmel.com/design-support/">Atmel Support</a>
  45. */
  46. #ifdef ARDUINO_ARCH_SAM
  47. #include "conf_usb.h"
  48. #include "usb_protocol.h"
  49. #include "usb_protocol_cdc.h"
  50. #include "udd.h"
  51. #include "udc.h"
  52. #include "udi_cdc.h"
  53. #include <string.h>
  54. #ifdef UDI_CDC_LOW_RATE
  55. # ifdef USB_DEVICE_HS_SUPPORT
  56. # define UDI_CDC_TX_BUFFERS (UDI_CDC_DATA_EPS_HS_SIZE)
  57. # define UDI_CDC_RX_BUFFERS (UDI_CDC_DATA_EPS_HS_SIZE)
  58. # else
  59. # define UDI_CDC_TX_BUFFERS (UDI_CDC_DATA_EPS_FS_SIZE)
  60. # define UDI_CDC_RX_BUFFERS (UDI_CDC_DATA_EPS_FS_SIZE)
  61. # endif
  62. #else
  63. # ifdef USB_DEVICE_HS_SUPPORT
  64. # define UDI_CDC_TX_BUFFERS (UDI_CDC_DATA_EPS_HS_SIZE)
  65. # define UDI_CDC_RX_BUFFERS (UDI_CDC_DATA_EPS_HS_SIZE)
  66. # else
  67. # define UDI_CDC_TX_BUFFERS (5*UDI_CDC_DATA_EPS_FS_SIZE)
  68. # define UDI_CDC_RX_BUFFERS (5*UDI_CDC_DATA_EPS_FS_SIZE)
  69. # endif
  70. #endif
  71. #ifndef UDI_CDC_TX_EMPTY_NOTIFY
  72. # define UDI_CDC_TX_EMPTY_NOTIFY(port)
  73. #endif
  74. /**
  75. * \ingroup udi_cdc_group
  76. * \defgroup udi_cdc_group_udc Interface with USB Device Core (UDC)
  77. *
  78. * Structures and functions required by UDC.
  79. *
  80. * @{
  81. */
  82. bool udi_cdc_comm_enable(void);
  83. void udi_cdc_comm_disable(void);
  84. bool udi_cdc_comm_setup(void);
  85. bool udi_cdc_data_enable(void);
  86. void udi_cdc_data_disable(void);
  87. bool udi_cdc_data_setup(void);
  88. uint8_t udi_cdc_getsetting(void);
  89. void udi_cdc_data_sof_notify(void);
  90. UDC_DESC_STORAGE udi_api_t udi_api_cdc_comm = {
  91. .enable = udi_cdc_comm_enable,
  92. .disable = udi_cdc_comm_disable,
  93. .setup = udi_cdc_comm_setup,
  94. .getsetting = udi_cdc_getsetting,
  95. };
  96. UDC_DESC_STORAGE udi_api_t udi_api_cdc_data = {
  97. .enable = udi_cdc_data_enable,
  98. .disable = udi_cdc_data_disable,
  99. .setup = udi_cdc_data_setup,
  100. .getsetting = udi_cdc_getsetting,
  101. .sof_notify = udi_cdc_data_sof_notify,
  102. };
  103. //@}
  104. /**
  105. * \ingroup udi_cdc_group
  106. * \defgroup udi_cdc_group_internal Implementation of UDI CDC
  107. *
  108. * Class internal implementation
  109. * @{
  110. */
  111. /**
  112. * \name Internal routines
  113. */
  114. //@{
  115. /**
  116. * \name Routines to control serial line
  117. */
  118. //@{
  119. /**
  120. * \brief Returns the port number corresponding at current setup request
  121. *
  122. * \return port number
  123. */
  124. static uint8_t udi_cdc_setup_to_port(void);
  125. /**
  126. * \brief Sends line coding to application
  127. *
  128. * Called after SETUP request when line coding data is received.
  129. */
  130. static void udi_cdc_line_coding_received(void);
  131. /**
  132. * \brief Records new state
  133. *
  134. * \param port Communication port number to manage
  135. * \param b_set State is enabled if true, else disabled
  136. * \param bit_mask Field to process (see CDC_SERIAL_STATE_ defines)
  137. */
  138. static void udi_cdc_ctrl_state_change(uint8_t port, bool b_set, le16_t bit_mask);
  139. /**
  140. * \brief Check and eventually notify the USB host of new state
  141. *
  142. * \param port Communication port number to manage
  143. * \param ep Port communication endpoint
  144. */
  145. static void udi_cdc_ctrl_state_notify(uint8_t port, udd_ep_id_t ep);
  146. /**
  147. * \brief Ack sent of serial state message
  148. * Callback called after serial state message sent
  149. *
  150. * \param status UDD_EP_TRANSFER_OK, if transfer finished
  151. * \param status UDD_EP_TRANSFER_ABORT, if transfer aborted
  152. * \param n number of data transfered
  153. */
  154. static void udi_cdc_serial_state_msg_sent(udd_ep_status_t status, iram_size_t n, udd_ep_id_t ep);
  155. //@}
  156. /**
  157. * \name Routines to process data transfer
  158. */
  159. //@{
  160. /**
  161. * \brief Enable the reception of data from the USB host
  162. *
  163. * The value udi_cdc_rx_trans_sel indicate the RX buffer to fill.
  164. *
  165. * \param port Communication port number to manage
  166. *
  167. * \return \c 1 if function was successfully done, otherwise \c 0.
  168. */
  169. static bool udi_cdc_rx_start(uint8_t port);
  170. /**
  171. * \brief Update rx buffer management with a new data
  172. * Callback called after data reception on USB line
  173. *
  174. * \param status UDD_EP_TRANSFER_OK, if transfer finish
  175. * \param status UDD_EP_TRANSFER_ABORT, if transfer aborted
  176. * \param n number of data received
  177. */
  178. static void udi_cdc_data_received(udd_ep_status_t status, iram_size_t n, udd_ep_id_t ep);
  179. /**
  180. * \brief Ack sent of tx buffer
  181. * Callback called after data transfer on USB line
  182. *
  183. * \param status UDD_EP_TRANSFER_OK, if transfer finished
  184. * \param status UDD_EP_TRANSFER_ABORT, if transfer aborted
  185. * \param n number of data transfered
  186. */
  187. static void udi_cdc_data_sent(udd_ep_status_t status, iram_size_t n, udd_ep_id_t ep);
  188. /**
  189. * \brief Send buffer on line or wait a SOF event
  190. *
  191. * \param port Communication port number to manage
  192. */
  193. static void udi_cdc_tx_send(uint8_t port);
  194. //@}
  195. //@}
  196. /**
  197. * \name Information about configuration of communication line
  198. */
  199. //@{
  200. COMPILER_WORD_ALIGNED
  201. static usb_cdc_line_coding_t udi_cdc_line_coding[UDI_CDC_PORT_NB];
  202. static bool udi_cdc_serial_state_msg_ongoing[UDI_CDC_PORT_NB];
  203. static volatile le16_t udi_cdc_state[UDI_CDC_PORT_NB];
  204. COMPILER_WORD_ALIGNED static usb_cdc_notify_serial_state_t uid_cdc_state_msg[UDI_CDC_PORT_NB];
  205. //! Status of CDC COMM interfaces
  206. static volatile uint8_t udi_cdc_nb_comm_enabled = 0;
  207. //@}
  208. /**
  209. * \name Variables to manage RX/TX transfer requests
  210. * Two buffers for each sense are used to optimize the speed.
  211. */
  212. //@{
  213. //! Status of CDC DATA interfaces
  214. static volatile uint8_t udi_cdc_nb_data_enabled = 0;
  215. static volatile bool udi_cdc_data_running = false;
  216. //! Buffer to receive data
  217. COMPILER_WORD_ALIGNED static uint8_t udi_cdc_rx_buf[UDI_CDC_PORT_NB][2][UDI_CDC_RX_BUFFERS];
  218. //! Data available in RX buffers
  219. static volatile uint16_t udi_cdc_rx_buf_nb[UDI_CDC_PORT_NB][2];
  220. //! Give the current RX buffer used (rx0 if 0, rx1 if 1)
  221. static volatile uint8_t udi_cdc_rx_buf_sel[UDI_CDC_PORT_NB];
  222. //! Read position in current RX buffer
  223. static volatile uint16_t udi_cdc_rx_pos[UDI_CDC_PORT_NB];
  224. //! Signal a transfer on-going
  225. static volatile bool udi_cdc_rx_trans_ongoing[UDI_CDC_PORT_NB];
  226. //! Define a transfer halted
  227. #define UDI_CDC_TRANS_HALTED 2
  228. //! Buffer to send data
  229. COMPILER_WORD_ALIGNED static uint8_t udi_cdc_tx_buf[UDI_CDC_PORT_NB][2][UDI_CDC_TX_BUFFERS];
  230. //! Data available in TX buffers
  231. static uint16_t udi_cdc_tx_buf_nb[UDI_CDC_PORT_NB][2];
  232. //! Give current TX buffer used (tx0 if 0, tx1 if 1)
  233. static volatile uint8_t udi_cdc_tx_buf_sel[UDI_CDC_PORT_NB];
  234. //! Value of SOF during last TX transfer
  235. static uint16_t udi_cdc_tx_sof_num[UDI_CDC_PORT_NB];
  236. //! Signal a transfer on-going
  237. static volatile bool udi_cdc_tx_trans_ongoing[UDI_CDC_PORT_NB];
  238. //! Signal that both buffer content data to send
  239. static volatile bool udi_cdc_tx_both_buf_to_send[UDI_CDC_PORT_NB];
  240. //@}
  241. bool udi_cdc_comm_enable(void)
  242. {
  243. uint8_t port;
  244. uint8_t iface_comm_num;
  245. #if UDI_CDC_PORT_NB == 1 // To optimize code
  246. port = 0;
  247. udi_cdc_nb_comm_enabled = 0;
  248. #else
  249. if (udi_cdc_nb_comm_enabled > UDI_CDC_PORT_NB) {
  250. udi_cdc_nb_comm_enabled = 0;
  251. }
  252. port = udi_cdc_nb_comm_enabled;
  253. #endif
  254. // Initialize control signal management
  255. udi_cdc_state[port] = CPU_TO_LE16(0);
  256. uid_cdc_state_msg[port].header.bmRequestType =
  257. USB_REQ_DIR_IN | USB_REQ_TYPE_CLASS |
  258. USB_REQ_RECIP_INTERFACE;
  259. uid_cdc_state_msg[port].header.bNotification = USB_REQ_CDC_NOTIFY_SERIAL_STATE;
  260. uid_cdc_state_msg[port].header.wValue = LE16(0);
  261. switch (port) {
  262. #define UDI_CDC_PORT_TO_IFACE_COMM(index, unused) \
  263. case index: \
  264. iface_comm_num = UDI_CDC_COMM_IFACE_NUMBER_##index; \
  265. break;
  266. MREPEAT(UDI_CDC_PORT_NB, UDI_CDC_PORT_TO_IFACE_COMM, ~)
  267. #undef UDI_CDC_PORT_TO_IFACE_COMM
  268. default:
  269. iface_comm_num = UDI_CDC_COMM_IFACE_NUMBER_0;
  270. break;
  271. }
  272. uid_cdc_state_msg[port].header.wIndex = LE16(iface_comm_num);
  273. uid_cdc_state_msg[port].header.wLength = LE16(2);
  274. uid_cdc_state_msg[port].value = CPU_TO_LE16(0);
  275. udi_cdc_line_coding[port].dwDTERate = CPU_TO_LE32(UDI_CDC_DEFAULT_RATE);
  276. udi_cdc_line_coding[port].bCharFormat = UDI_CDC_DEFAULT_STOPBITS;
  277. udi_cdc_line_coding[port].bParityType = UDI_CDC_DEFAULT_PARITY;
  278. udi_cdc_line_coding[port].bDataBits = UDI_CDC_DEFAULT_DATABITS;
  279. // Call application callback
  280. // to initialize memories or indicate that interface is enabled
  281. UDI_CDC_SET_CODING_EXT(port,(&udi_cdc_line_coding[port]));
  282. if (!UDI_CDC_ENABLE_EXT(port)) {
  283. return false;
  284. }
  285. udi_cdc_nb_comm_enabled++;
  286. return true;
  287. }
  288. bool udi_cdc_data_enable(void)
  289. {
  290. uint8_t port;
  291. #if UDI_CDC_PORT_NB == 1 // To optimize code
  292. port = 0;
  293. udi_cdc_nb_data_enabled = 0;
  294. #else
  295. if (udi_cdc_nb_data_enabled > UDI_CDC_PORT_NB) {
  296. udi_cdc_nb_data_enabled = 0;
  297. }
  298. port = udi_cdc_nb_data_enabled;
  299. #endif
  300. // Initialize TX management
  301. udi_cdc_tx_trans_ongoing[port] = false;
  302. udi_cdc_tx_both_buf_to_send[port] = false;
  303. udi_cdc_tx_buf_sel[port] = 0;
  304. udi_cdc_tx_buf_nb[port][0] = 0;
  305. udi_cdc_tx_buf_nb[port][1] = 0;
  306. udi_cdc_tx_sof_num[port] = 0;
  307. udi_cdc_tx_send(port);
  308. // Initialize RX management
  309. udi_cdc_rx_trans_ongoing[port] = false;
  310. udi_cdc_rx_buf_sel[port] = 0;
  311. udi_cdc_rx_buf_nb[port][0] = 0;
  312. udi_cdc_rx_buf_nb[port][1] = 0;
  313. udi_cdc_rx_pos[port] = 0;
  314. if (!udi_cdc_rx_start(port)) {
  315. return false;
  316. }
  317. udi_cdc_nb_data_enabled++;
  318. if (udi_cdc_nb_data_enabled == UDI_CDC_PORT_NB) {
  319. udi_cdc_data_running = true;
  320. }
  321. return true;
  322. }
  323. void udi_cdc_comm_disable(void)
  324. {
  325. Assert(udi_cdc_nb_comm_enabled != 0);
  326. udi_cdc_nb_comm_enabled--;
  327. }
  328. void udi_cdc_data_disable(void)
  329. {
  330. uint8_t port;
  331. Assert(udi_cdc_nb_data_enabled != 0);
  332. udi_cdc_nb_data_enabled--;
  333. port = udi_cdc_nb_data_enabled;
  334. UDI_CDC_DISABLE_EXT(port);
  335. udi_cdc_data_running = false;
  336. }
  337. bool udi_cdc_comm_setup(void)
  338. {
  339. uint8_t port = udi_cdc_setup_to_port();
  340. if (Udd_setup_is_in()) {
  341. // GET Interface Requests
  342. if (Udd_setup_type() == USB_REQ_TYPE_CLASS) {
  343. // Requests Class Interface Get
  344. switch (udd_g_ctrlreq.req.bRequest) {
  345. case USB_REQ_CDC_GET_LINE_CODING:
  346. // Get configuration of CDC line
  347. if (sizeof(usb_cdc_line_coding_t) !=
  348. udd_g_ctrlreq.req.wLength)
  349. return false; // Error for USB host
  350. udd_g_ctrlreq.payload =
  351. (uint8_t *) &
  352. udi_cdc_line_coding[port];
  353. udd_g_ctrlreq.payload_size =
  354. sizeof(usb_cdc_line_coding_t);
  355. return true;
  356. }
  357. }
  358. }
  359. if (Udd_setup_is_out()) {
  360. // SET Interface Requests
  361. if (Udd_setup_type() == USB_REQ_TYPE_CLASS) {
  362. // Requests Class Interface Set
  363. switch (udd_g_ctrlreq.req.bRequest) {
  364. case USB_REQ_CDC_SET_LINE_CODING:
  365. // Change configuration of CDC line
  366. if (sizeof(usb_cdc_line_coding_t) !=
  367. udd_g_ctrlreq.req.wLength)
  368. return false; // Error for USB host
  369. udd_g_ctrlreq.callback =
  370. udi_cdc_line_coding_received;
  371. udd_g_ctrlreq.payload =
  372. (uint8_t *) &
  373. udi_cdc_line_coding[port];
  374. udd_g_ctrlreq.payload_size =
  375. sizeof(usb_cdc_line_coding_t);
  376. return true;
  377. case USB_REQ_CDC_SET_CONTROL_LINE_STATE:
  378. // According cdc spec 1.1 chapter 6.2.14
  379. UDI_CDC_SET_DTR_EXT(port, (0 !=
  380. (udd_g_ctrlreq.req.wValue
  381. & CDC_CTRL_SIGNAL_DTE_PRESENT)));
  382. UDI_CDC_SET_RTS_EXT(port, (0 !=
  383. (udd_g_ctrlreq.req.wValue
  384. & CDC_CTRL_SIGNAL_ACTIVATE_CARRIER)));
  385. return true;
  386. }
  387. }
  388. }
  389. return false; // request Not supported
  390. }
  391. bool udi_cdc_data_setup(void)
  392. {
  393. return false; // request Not supported
  394. }
  395. uint8_t udi_cdc_getsetting(void)
  396. {
  397. return 0; // CDC don't have multiple alternate setting
  398. }
  399. void udi_cdc_data_sof_notify(void)
  400. {
  401. static uint8_t port_notify = 0;
  402. // A call of udi_cdc_data_sof_notify() is done for each port
  403. udi_cdc_tx_send(port_notify);
  404. #if UDI_CDC_PORT_NB != 1 // To optimize code
  405. port_notify++;
  406. if (port_notify >= UDI_CDC_PORT_NB) {
  407. port_notify = 0;
  408. }
  409. #endif
  410. }
  411. // ------------------------
  412. //------- Internal routines to control serial line
  413. static uint8_t udi_cdc_setup_to_port(void)
  414. {
  415. uint8_t port;
  416. switch (udd_g_ctrlreq.req.wIndex & 0xFF) {
  417. #define UDI_CDC_IFACE_COMM_TO_PORT(iface, unused) \
  418. case UDI_CDC_COMM_IFACE_NUMBER_##iface: \
  419. port = iface; \
  420. break;
  421. MREPEAT(UDI_CDC_PORT_NB, UDI_CDC_IFACE_COMM_TO_PORT, ~)
  422. #undef UDI_CDC_IFACE_COMM_TO_PORT
  423. default:
  424. port = 0;
  425. break;
  426. }
  427. return port;
  428. }
  429. static void udi_cdc_line_coding_received(void)
  430. {
  431. uint8_t port = udi_cdc_setup_to_port();
  432. UNUSED(port);
  433. UDI_CDC_SET_CODING_EXT(port, (&udi_cdc_line_coding[port]));
  434. }
  435. static void udi_cdc_ctrl_state_change(uint8_t port, bool b_set, le16_t bit_mask)
  436. {
  437. irqflags_t flags;
  438. udd_ep_id_t ep_comm;
  439. #if UDI_CDC_PORT_NB == 1 // To optimize code
  440. port = 0;
  441. #endif
  442. // Update state
  443. flags = cpu_irq_save(); // Protect udi_cdc_state
  444. if (b_set) {
  445. udi_cdc_state[port] |= bit_mask;
  446. } else {
  447. udi_cdc_state[port] &= ~(unsigned)bit_mask;
  448. }
  449. cpu_irq_restore(flags);
  450. // Send it if possible and state changed
  451. switch (port) {
  452. #define UDI_CDC_PORT_TO_COMM_EP(index, unused) \
  453. case index: \
  454. ep_comm = UDI_CDC_COMM_EP_##index; \
  455. break;
  456. MREPEAT(UDI_CDC_PORT_NB, UDI_CDC_PORT_TO_COMM_EP, ~)
  457. #undef UDI_CDC_PORT_TO_COMM_EP
  458. default:
  459. ep_comm = UDI_CDC_COMM_EP_0;
  460. break;
  461. }
  462. udi_cdc_ctrl_state_notify(port, ep_comm);
  463. }
  464. static void udi_cdc_ctrl_state_notify(uint8_t port, udd_ep_id_t ep)
  465. {
  466. #if UDI_CDC_PORT_NB == 1 // To optimize code
  467. port = 0;
  468. #endif
  469. // Send it if possible and state changed
  470. if ((!udi_cdc_serial_state_msg_ongoing[port])
  471. && (udi_cdc_state[port] != uid_cdc_state_msg[port].value)) {
  472. // Fill notification message
  473. uid_cdc_state_msg[port].value = udi_cdc_state[port];
  474. // Send notification message
  475. udi_cdc_serial_state_msg_ongoing[port] =
  476. udd_ep_run(ep,
  477. false,
  478. (uint8_t *) & uid_cdc_state_msg[port],
  479. sizeof(uid_cdc_state_msg[0]),
  480. udi_cdc_serial_state_msg_sent);
  481. }
  482. }
  483. static void udi_cdc_serial_state_msg_sent(udd_ep_status_t status, iram_size_t n, udd_ep_id_t ep)
  484. {
  485. uint8_t port;
  486. UNUSED(n);
  487. UNUSED(status);
  488. switch (ep) {
  489. #define UDI_CDC_GET_PORT_FROM_COMM_EP(iface, unused) \
  490. case UDI_CDC_COMM_EP_##iface: \
  491. port = iface; \
  492. break;
  493. MREPEAT(UDI_CDC_PORT_NB, UDI_CDC_GET_PORT_FROM_COMM_EP, ~)
  494. #undef UDI_CDC_GET_PORT_FROM_COMM_EP
  495. default:
  496. port = 0;
  497. break;
  498. }
  499. udi_cdc_serial_state_msg_ongoing[port] = false;
  500. // For the irregular signals like break, the incoming ring signal,
  501. // or the overrun error state, this will reset their values to zero
  502. // and again will not send another notification until their state changes.
  503. udi_cdc_state[port] &= ~(CDC_SERIAL_STATE_BREAK |
  504. CDC_SERIAL_STATE_RING |
  505. CDC_SERIAL_STATE_FRAMING |
  506. CDC_SERIAL_STATE_PARITY | CDC_SERIAL_STATE_OVERRUN);
  507. uid_cdc_state_msg[port].value &= ~(CDC_SERIAL_STATE_BREAK |
  508. CDC_SERIAL_STATE_RING |
  509. CDC_SERIAL_STATE_FRAMING |
  510. CDC_SERIAL_STATE_PARITY | CDC_SERIAL_STATE_OVERRUN);
  511. // Send it if possible and state changed
  512. udi_cdc_ctrl_state_notify(port, ep);
  513. }
  514. // ------------------------
  515. //------- Internal routines to process data transfer
  516. static bool udi_cdc_rx_start(uint8_t port)
  517. {
  518. irqflags_t flags;
  519. uint8_t buf_sel_trans;
  520. udd_ep_id_t ep;
  521. #if UDI_CDC_PORT_NB == 1 // To optimize code
  522. port = 0;
  523. #endif
  524. flags = cpu_irq_save();
  525. buf_sel_trans = udi_cdc_rx_buf_sel[port];
  526. if (udi_cdc_rx_trans_ongoing[port] ||
  527. (udi_cdc_rx_pos[port] < udi_cdc_rx_buf_nb[port][buf_sel_trans])) {
  528. // Transfer already on-going or current buffer no empty
  529. cpu_irq_restore(flags);
  530. return false;
  531. }
  532. // Change current buffer
  533. udi_cdc_rx_pos[port] = 0;
  534. udi_cdc_rx_buf_sel[port] = (buf_sel_trans==0)?1:0;
  535. // Start transfer on RX
  536. udi_cdc_rx_trans_ongoing[port] = true;
  537. cpu_irq_restore(flags);
  538. if (udi_cdc_multi_is_rx_ready(port)) {
  539. UDI_CDC_RX_NOTIFY(port);
  540. }
  541. // Send the buffer with enable of short packet
  542. switch (port) {
  543. #define UDI_CDC_PORT_TO_DATA_EP_OUT(index, unused) \
  544. case index: \
  545. ep = UDI_CDC_DATA_EP_OUT_##index; \
  546. break;
  547. MREPEAT(UDI_CDC_PORT_NB, UDI_CDC_PORT_TO_DATA_EP_OUT, ~)
  548. #undef UDI_CDC_PORT_TO_DATA_EP_OUT
  549. default:
  550. ep = UDI_CDC_DATA_EP_OUT_0;
  551. break;
  552. }
  553. return udd_ep_run(ep,
  554. true,
  555. udi_cdc_rx_buf[port][buf_sel_trans],
  556. UDI_CDC_RX_BUFFERS,
  557. udi_cdc_data_received);
  558. }
  559. static void udi_cdc_data_received(udd_ep_status_t status, iram_size_t n, udd_ep_id_t ep)
  560. {
  561. uint8_t buf_sel_trans;
  562. uint8_t port;
  563. switch (ep) {
  564. #define UDI_CDC_DATA_EP_OUT_TO_PORT(index, unused) \
  565. case UDI_CDC_DATA_EP_OUT_##index: \
  566. port = index; \
  567. break;
  568. MREPEAT(UDI_CDC_PORT_NB, UDI_CDC_DATA_EP_OUT_TO_PORT, ~)
  569. #undef UDI_CDC_DATA_EP_OUT_TO_PORT
  570. default:
  571. port = 0;
  572. break;
  573. }
  574. if (UDD_EP_TRANSFER_OK != status) {
  575. // Abort reception
  576. return;
  577. }
  578. buf_sel_trans = (udi_cdc_rx_buf_sel[port]==0)?1:0;
  579. if (!n) {
  580. udd_ep_run( ep,
  581. true,
  582. udi_cdc_rx_buf[port][buf_sel_trans],
  583. UDI_CDC_RX_BUFFERS,
  584. udi_cdc_data_received);
  585. return;
  586. }
  587. udi_cdc_rx_buf_nb[port][buf_sel_trans] = n;
  588. udi_cdc_rx_trans_ongoing[port] = false;
  589. udi_cdc_rx_start(port);
  590. }
  591. static void udi_cdc_data_sent(udd_ep_status_t status, iram_size_t n, udd_ep_id_t ep)
  592. {
  593. uint8_t port;
  594. UNUSED(n);
  595. switch (ep) {
  596. #define UDI_CDC_DATA_EP_IN_TO_PORT(index, unused) \
  597. case UDI_CDC_DATA_EP_IN_##index: \
  598. port = index; \
  599. break;
  600. MREPEAT(UDI_CDC_PORT_NB, UDI_CDC_DATA_EP_IN_TO_PORT, ~)
  601. #undef UDI_CDC_DATA_EP_IN_TO_PORT
  602. default:
  603. port = 0;
  604. break;
  605. }
  606. if (UDD_EP_TRANSFER_OK != status) {
  607. // Abort transfer
  608. return;
  609. }
  610. udi_cdc_tx_buf_nb[port][(udi_cdc_tx_buf_sel[port]==0)?1:0] = 0;
  611. udi_cdc_tx_both_buf_to_send[port] = false;
  612. udi_cdc_tx_trans_ongoing[port] = false;
  613. if (n != 0) {
  614. UDI_CDC_TX_EMPTY_NOTIFY(port);
  615. }
  616. udi_cdc_tx_send(port);
  617. }
  618. static void udi_cdc_tx_send(uint8_t port)
  619. {
  620. irqflags_t flags;
  621. uint8_t buf_sel_trans;
  622. bool b_short_packet;
  623. udd_ep_id_t ep;
  624. static uint16_t sof_zlp_counter = 0;
  625. #if UDI_CDC_PORT_NB == 1 // To optimize code
  626. port = 0;
  627. #endif
  628. if (udi_cdc_tx_trans_ongoing[port]) {
  629. return; // Already on going or wait next SOF to send next data
  630. }
  631. if (udd_is_high_speed()) {
  632. if (udi_cdc_tx_sof_num[port] == udd_get_micro_frame_number()) {
  633. return; // Wait next SOF to send next data
  634. }
  635. }else{
  636. if (udi_cdc_tx_sof_num[port] == udd_get_frame_number()) {
  637. return; // Wait next SOF to send next data
  638. }
  639. }
  640. flags = cpu_irq_save(); // to protect udi_cdc_tx_buf_sel
  641. buf_sel_trans = udi_cdc_tx_buf_sel[port];
  642. if (udi_cdc_tx_buf_nb[port][buf_sel_trans] == 0) {
  643. sof_zlp_counter++;
  644. if (((!udd_is_high_speed()) && (sof_zlp_counter < 100))
  645. || (udd_is_high_speed() && (sof_zlp_counter < 800))) {
  646. cpu_irq_restore(flags);
  647. return;
  648. }
  649. }
  650. sof_zlp_counter = 0;
  651. if (!udi_cdc_tx_both_buf_to_send[port]) {
  652. // Send current Buffer
  653. // and switch the current buffer
  654. udi_cdc_tx_buf_sel[port] = (buf_sel_trans==0)?1:0;
  655. }else{
  656. // Send the other Buffer
  657. // and no switch the current buffer
  658. buf_sel_trans = (buf_sel_trans==0)?1:0;
  659. }
  660. udi_cdc_tx_trans_ongoing[port] = true;
  661. cpu_irq_restore(flags);
  662. b_short_packet = (udi_cdc_tx_buf_nb[port][buf_sel_trans] != UDI_CDC_TX_BUFFERS);
  663. if (b_short_packet) {
  664. if (udd_is_high_speed()) {
  665. udi_cdc_tx_sof_num[port] = udd_get_micro_frame_number();
  666. }else{
  667. udi_cdc_tx_sof_num[port] = udd_get_frame_number();
  668. }
  669. }else{
  670. udi_cdc_tx_sof_num[port] = 0; // Force next transfer without wait SOF
  671. }
  672. // Send the buffer with enable of short packet
  673. switch (port) {
  674. #define UDI_CDC_PORT_TO_DATA_EP_IN(index, unused) \
  675. case index: \
  676. ep = UDI_CDC_DATA_EP_IN_##index; \
  677. break;
  678. MREPEAT(UDI_CDC_PORT_NB, UDI_CDC_PORT_TO_DATA_EP_IN, ~)
  679. #undef UDI_CDC_PORT_TO_DATA_EP_IN
  680. default:
  681. ep = UDI_CDC_DATA_EP_IN_0;
  682. break;
  683. }
  684. udd_ep_run( ep,
  685. b_short_packet,
  686. udi_cdc_tx_buf[port][buf_sel_trans],
  687. udi_cdc_tx_buf_nb[port][buf_sel_trans],
  688. udi_cdc_data_sent);
  689. }
  690. // ------------------------
  691. //------- Application interface
  692. //------- Application interface
  693. void udi_cdc_ctrl_signal_dcd(bool b_set)
  694. {
  695. udi_cdc_ctrl_state_change(0, b_set, CDC_SERIAL_STATE_DCD);
  696. }
  697. void udi_cdc_ctrl_signal_dsr(bool b_set)
  698. {
  699. udi_cdc_ctrl_state_change(0, b_set, CDC_SERIAL_STATE_DSR);
  700. }
  701. void udi_cdc_signal_framing_error(void)
  702. {
  703. udi_cdc_ctrl_state_change(0, true, CDC_SERIAL_STATE_FRAMING);
  704. }
  705. void udi_cdc_signal_parity_error(void)
  706. {
  707. udi_cdc_ctrl_state_change(0, true, CDC_SERIAL_STATE_PARITY);
  708. }
  709. void udi_cdc_signal_overrun(void)
  710. {
  711. udi_cdc_ctrl_state_change(0, true, CDC_SERIAL_STATE_OVERRUN);
  712. }
  713. void udi_cdc_multi_ctrl_signal_dcd(uint8_t port, bool b_set)
  714. {
  715. udi_cdc_ctrl_state_change(port, b_set, CDC_SERIAL_STATE_DCD);
  716. }
  717. void udi_cdc_multi_ctrl_signal_dsr(uint8_t port, bool b_set)
  718. {
  719. udi_cdc_ctrl_state_change(port, b_set, CDC_SERIAL_STATE_DSR);
  720. }
  721. void udi_cdc_multi_signal_framing_error(uint8_t port)
  722. {
  723. udi_cdc_ctrl_state_change(port, true, CDC_SERIAL_STATE_FRAMING);
  724. }
  725. void udi_cdc_multi_signal_parity_error(uint8_t port)
  726. {
  727. udi_cdc_ctrl_state_change(port, true, CDC_SERIAL_STATE_PARITY);
  728. }
  729. void udi_cdc_multi_signal_overrun(uint8_t port)
  730. {
  731. udi_cdc_ctrl_state_change(port, true, CDC_SERIAL_STATE_OVERRUN);
  732. }
  733. iram_size_t udi_cdc_multi_get_nb_received_data(uint8_t port)
  734. {
  735. irqflags_t flags;
  736. uint16_t pos;
  737. iram_size_t nb_received;
  738. #if UDI_CDC_PORT_NB == 1 // To optimize code
  739. port = 0;
  740. #endif
  741. flags = cpu_irq_save();
  742. pos = udi_cdc_rx_pos[port];
  743. nb_received = udi_cdc_rx_buf_nb[port][udi_cdc_rx_buf_sel[port]] - pos;
  744. cpu_irq_restore(flags);
  745. return nb_received;
  746. }
  747. iram_size_t udi_cdc_get_nb_received_data(void)
  748. {
  749. return udi_cdc_multi_get_nb_received_data(0);
  750. }
  751. bool udi_cdc_multi_is_rx_ready(uint8_t port)
  752. {
  753. return (udi_cdc_multi_get_nb_received_data(port) > 0);
  754. }
  755. bool udi_cdc_is_rx_ready(void)
  756. {
  757. return udi_cdc_multi_is_rx_ready(0);
  758. }
  759. int udi_cdc_multi_getc(uint8_t port)
  760. {
  761. irqflags_t flags;
  762. int rx_data = 0;
  763. bool b_databit_9;
  764. uint16_t pos;
  765. uint8_t buf_sel;
  766. bool again;
  767. #if UDI_CDC_PORT_NB == 1 // To optimize code
  768. port = 0;
  769. #endif
  770. b_databit_9 = (9 == udi_cdc_line_coding[port].bDataBits);
  771. udi_cdc_getc_process_one_byte:
  772. // Check available data
  773. flags = cpu_irq_save();
  774. pos = udi_cdc_rx_pos[port];
  775. buf_sel = udi_cdc_rx_buf_sel[port];
  776. again = pos >= udi_cdc_rx_buf_nb[port][buf_sel];
  777. cpu_irq_restore(flags);
  778. while (again) {
  779. if (!udi_cdc_data_running) {
  780. return 0;
  781. }
  782. goto udi_cdc_getc_process_one_byte;
  783. }
  784. // Read data
  785. rx_data |= udi_cdc_rx_buf[port][buf_sel][pos];
  786. udi_cdc_rx_pos[port] = pos+1;
  787. udi_cdc_rx_start(port);
  788. if (b_databit_9) {
  789. // Receive MSB
  790. b_databit_9 = false;
  791. rx_data = rx_data << 8;
  792. goto udi_cdc_getc_process_one_byte;
  793. }
  794. return rx_data;
  795. }
  796. int udi_cdc_getc(void)
  797. {
  798. return udi_cdc_multi_getc(0);
  799. }
  800. iram_size_t udi_cdc_multi_read_buf(uint8_t port, void* buf, iram_size_t size)
  801. {
  802. irqflags_t flags;
  803. uint8_t *ptr_buf = (uint8_t *)buf;
  804. iram_size_t copy_nb;
  805. uint16_t pos;
  806. uint8_t buf_sel;
  807. bool again;
  808. #if UDI_CDC_PORT_NB == 1 // To optimize code
  809. port = 0;
  810. #endif
  811. udi_cdc_read_buf_loop_wait:
  812. // Check available data
  813. flags = cpu_irq_save();
  814. pos = udi_cdc_rx_pos[port];
  815. buf_sel = udi_cdc_rx_buf_sel[port];
  816. again = pos >= udi_cdc_rx_buf_nb[port][buf_sel];
  817. cpu_irq_restore(flags);
  818. while (again) {
  819. if (!udi_cdc_data_running) {
  820. return size;
  821. }
  822. goto udi_cdc_read_buf_loop_wait;
  823. }
  824. // Read data
  825. copy_nb = udi_cdc_rx_buf_nb[port][buf_sel] - pos;
  826. if (copy_nb>size) {
  827. copy_nb = size;
  828. }
  829. memcpy(ptr_buf, &udi_cdc_rx_buf[port][buf_sel][pos], copy_nb);
  830. udi_cdc_rx_pos[port] += copy_nb;
  831. ptr_buf += copy_nb;
  832. size -= copy_nb;
  833. udi_cdc_rx_start(port);
  834. if (size) {
  835. goto udi_cdc_read_buf_loop_wait;
  836. }
  837. return 0;
  838. }
  839. static iram_size_t udi_cdc_multi_read_no_polling(uint8_t port, void* buf, iram_size_t size)
  840. {
  841. uint8_t *ptr_buf = (uint8_t *)buf;
  842. iram_size_t nb_avail_data;
  843. uint16_t pos;
  844. uint8_t buf_sel;
  845. irqflags_t flags;
  846. #if UDI_CDC_PORT_NB == 1 // To optimize code
  847. port = 0;
  848. #endif
  849. //Data interface not started... exit
  850. if (!udi_cdc_data_running) {
  851. return 0;
  852. }
  853. //Get number of available data
  854. // Check available data
  855. flags = cpu_irq_save(); // to protect udi_cdc_rx_pos & udi_cdc_rx_buf_sel
  856. pos = udi_cdc_rx_pos[port];
  857. buf_sel = udi_cdc_rx_buf_sel[port];
  858. nb_avail_data = udi_cdc_rx_buf_nb[port][buf_sel] - pos;
  859. cpu_irq_restore(flags);
  860. //If the buffer contains less than the requested number of data,
  861. //adjust read size
  862. if(nb_avail_data<size) {
  863. size = nb_avail_data;
  864. }
  865. if(size>0) {
  866. memcpy(ptr_buf, &udi_cdc_rx_buf[port][buf_sel][pos], size);
  867. flags = cpu_irq_save(); // to protect udi_cdc_rx_pos
  868. udi_cdc_rx_pos[port] += size;
  869. cpu_irq_restore(flags);
  870. ptr_buf += size;
  871. udi_cdc_rx_start(port);
  872. }
  873. return(nb_avail_data);
  874. }
  875. iram_size_t udi_cdc_read_no_polling(void* buf, iram_size_t size)
  876. {
  877. return udi_cdc_multi_read_no_polling(0, buf, size);
  878. }
  879. iram_size_t udi_cdc_read_buf(void* buf, iram_size_t size)
  880. {
  881. return udi_cdc_multi_read_buf(0, buf, size);
  882. }
  883. iram_size_t __attribute__((optimize("O0"))) udi_cdc_multi_get_free_tx_buffer(uint8_t port)
  884. {
  885. irqflags_t flags;
  886. iram_size_t buf_sel_nb, retval;
  887. uint8_t buf_sel;
  888. #if UDI_CDC_PORT_NB == 1 // To optimize code
  889. port = 0;
  890. #endif
  891. flags = cpu_irq_save();
  892. buf_sel = udi_cdc_tx_buf_sel[port];
  893. buf_sel_nb = udi_cdc_tx_buf_nb[port][buf_sel];
  894. if (buf_sel_nb == UDI_CDC_TX_BUFFERS) {
  895. if ((!udi_cdc_tx_trans_ongoing[port])
  896. && (!udi_cdc_tx_both_buf_to_send[port])) {
  897. /* One buffer is full, but the other buffer is not used.
  898. * (not used = transfer on-going)
  899. * then move to the other buffer to store data */
  900. udi_cdc_tx_both_buf_to_send[port] = true;
  901. udi_cdc_tx_buf_sel[port] = (buf_sel == 0)? 1 : 0;
  902. buf_sel_nb = 0;
  903. }
  904. }
  905. retval = UDI_CDC_TX_BUFFERS - buf_sel_nb;
  906. cpu_irq_restore(flags);
  907. return retval;
  908. }
  909. iram_size_t udi_cdc_get_free_tx_buffer(void)
  910. {
  911. return udi_cdc_multi_get_free_tx_buffer(0);
  912. }
  913. bool udi_cdc_multi_is_tx_ready(uint8_t port)
  914. {
  915. return (udi_cdc_multi_get_free_tx_buffer(port) != 0);
  916. }
  917. bool udi_cdc_is_tx_ready(void)
  918. {
  919. return udi_cdc_multi_is_tx_ready(0);
  920. }
  921. int udi_cdc_multi_putc(uint8_t port, int value)
  922. {
  923. irqflags_t flags;
  924. bool b_databit_9;
  925. uint8_t buf_sel;
  926. #if UDI_CDC_PORT_NB == 1 // To optimize code
  927. port = 0;
  928. #endif
  929. b_databit_9 = (9 == udi_cdc_line_coding[port].bDataBits);
  930. udi_cdc_putc_process_one_byte:
  931. // Check available space
  932. if (!udi_cdc_multi_is_tx_ready(port)) {
  933. if (!udi_cdc_data_running) {
  934. return false;
  935. }
  936. goto udi_cdc_putc_process_one_byte;
  937. }
  938. // Write value
  939. flags = cpu_irq_save();
  940. buf_sel = udi_cdc_tx_buf_sel[port];
  941. udi_cdc_tx_buf[port][buf_sel][udi_cdc_tx_buf_nb[port][buf_sel]++] = value;
  942. cpu_irq_restore(flags);
  943. if (b_databit_9) {
  944. // Send MSB
  945. b_databit_9 = false;
  946. value = value >> 8;
  947. goto udi_cdc_putc_process_one_byte;
  948. }
  949. return true;
  950. }
  951. int udi_cdc_putc(int value)
  952. {
  953. return udi_cdc_multi_putc(0, value);
  954. }
  955. iram_size_t __attribute__((optimize("O0"))) udi_cdc_multi_write_buf(uint8_t port, const void* buf, iram_size_t size)
  956. {
  957. irqflags_t flags;
  958. uint8_t buf_sel;
  959. uint16_t buf_nb;
  960. iram_size_t copy_nb;
  961. uint8_t *ptr_buf = (uint8_t *)buf;
  962. #if UDI_CDC_PORT_NB == 1 // To optimize code
  963. port = 0;
  964. #endif
  965. if (9 == udi_cdc_line_coding[port].bDataBits) {
  966. size *=2;
  967. }
  968. udi_cdc_write_buf_loop_wait:
  969. // Check available space
  970. if (!udi_cdc_multi_is_tx_ready(port)) {
  971. if (!udi_cdc_data_running) {
  972. return size;
  973. }
  974. goto udi_cdc_write_buf_loop_wait;
  975. }
  976. // Write values
  977. flags = cpu_irq_save();
  978. buf_sel = udi_cdc_tx_buf_sel[port];
  979. buf_nb = udi_cdc_tx_buf_nb[port][buf_sel];
  980. copy_nb = UDI_CDC_TX_BUFFERS - buf_nb;
  981. if (copy_nb > size) {
  982. copy_nb = size;
  983. }
  984. memcpy(&udi_cdc_tx_buf[port][buf_sel][buf_nb], ptr_buf, copy_nb);
  985. udi_cdc_tx_buf_nb[port][buf_sel] = buf_nb + copy_nb;
  986. cpu_irq_restore(flags);
  987. // Update buffer pointer
  988. ptr_buf = ptr_buf + copy_nb;
  989. size -= copy_nb;
  990. if (size) {
  991. goto udi_cdc_write_buf_loop_wait;
  992. }
  993. return 0;
  994. }
  995. iram_size_t udi_cdc_write_buf(const void* buf, iram_size_t size)
  996. {
  997. return udi_cdc_multi_write_buf(0, buf, size);
  998. }
  999. //@}
  1000. #endif // ARDUINO_ARCH_SAM