cdc_device.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406
  1. /*
  2. * The MIT License (MIT)
  3. *
  4. * Copyright (c) 2019 Ha Thach (tinyusb.org)
  5. *
  6. * Permission is hereby granted, free of charge, to any person obtaining a copy
  7. * of this software and associated documentation files (the "Software"), to deal
  8. * in the Software without restriction, including without limitation the rights
  9. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  10. * copies of the Software, and to permit persons to whom the Software is
  11. * furnished to do so, subject to the following conditions:
  12. *
  13. * The above copyright notice and this permission notice shall be included in
  14. * all copies or substantial portions of the Software.
  15. *
  16. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  18. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  19. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  20. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  21. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  22. * THE SOFTWARE.
  23. *
  24. * This file is part of the TinyUSB stack.
  25. */
  26. #include "tusb_option.h"
  27. #if (TUSB_OPT_DEVICE_ENABLED && CFG_TUD_CDC)
  28. #include "cdc_device.h"
  29. #include "device/usbd_pvt.h"
  30. //--------------------------------------------------------------------+
  31. // MACRO CONSTANT TYPEDEF
  32. //--------------------------------------------------------------------+
  33. typedef struct
  34. {
  35. uint8_t itf_num;
  36. uint8_t ep_notif;
  37. uint8_t ep_in;
  38. uint8_t ep_out;
  39. // Bit 0: DTR (Data Terminal Ready), Bit 1: RTS (Request to Send)
  40. uint8_t line_state;
  41. /*------------- From this point, data is not cleared by bus reset -------------*/
  42. char wanted_char;
  43. cdc_line_coding_t line_coding;
  44. // FIFO
  45. tu_fifo_t rx_ff;
  46. tu_fifo_t tx_ff;
  47. uint8_t rx_ff_buf[CFG_TUD_CDC_RX_BUFSIZE];
  48. uint8_t tx_ff_buf[CFG_TUD_CDC_TX_BUFSIZE];
  49. #if CFG_FIFO_MUTEX
  50. osal_mutex_def_t rx_ff_mutex;
  51. osal_mutex_def_t tx_ff_mutex;
  52. #endif
  53. // Endpoint Transfer buffer
  54. CFG_TUSB_MEM_ALIGN uint8_t epout_buf[CFG_TUD_CDC_EPSIZE];
  55. CFG_TUSB_MEM_ALIGN uint8_t epin_buf[CFG_TUD_CDC_EPSIZE];
  56. }cdcd_interface_t;
  57. #define ITF_MEM_RESET_SIZE offsetof(cdcd_interface_t, wanted_char)
  58. //--------------------------------------------------------------------+
  59. // INTERNAL OBJECT & FUNCTION DECLARATION
  60. //--------------------------------------------------------------------+
  61. CFG_TUSB_MEM_SECTION static cdcd_interface_t _cdcd_itf[CFG_TUD_CDC];
  62. // TODO will be replaced by dcd_edpt_busy()
  63. bool pending_read_from_host;
  64. static void _prep_out_transaction (uint8_t itf)
  65. {
  66. cdcd_interface_t* p_cdc = &_cdcd_itf[itf];
  67. // skip if previous transfer not complete
  68. // dcd_edpt_busy() doesn't work, probably transfer is complete but not properly handled by the stack
  69. // if ( dcd_edpt_busy(TUD_OPT_RHPORT, p_cdc->ep_out) ) return;
  70. if (pending_read_from_host) return;
  71. // Prepare for incoming data but only allow what we can store in the ring buffer.
  72. uint16_t max_read = tu_fifo_remaining(&p_cdc->rx_ff);
  73. if ( max_read >= CFG_TUD_CDC_EPSIZE )
  74. {
  75. dcd_edpt_xfer(TUD_OPT_RHPORT, p_cdc->ep_out, p_cdc->epout_buf, CFG_TUD_CDC_EPSIZE);
  76. pending_read_from_host = true;
  77. }
  78. }
  79. //--------------------------------------------------------------------+
  80. // APPLICATION API
  81. //--------------------------------------------------------------------+
  82. bool tud_cdc_n_connected(uint8_t itf)
  83. {
  84. // DTR (bit 0) active is considered as connected
  85. return tud_ready() && tu_bit_test(_cdcd_itf[itf].line_state, 0);
  86. }
  87. uint8_t tud_cdc_n_get_line_state (uint8_t itf)
  88. {
  89. return _cdcd_itf[itf].line_state;
  90. }
  91. void tud_cdc_n_get_line_coding (uint8_t itf, cdc_line_coding_t* coding)
  92. {
  93. (*coding) = _cdcd_itf[itf].line_coding;
  94. }
  95. void tud_cdc_n_set_wanted_char (uint8_t itf, char wanted)
  96. {
  97. _cdcd_itf[itf].wanted_char = wanted;
  98. }
  99. //--------------------------------------------------------------------+
  100. // READ API
  101. //--------------------------------------------------------------------+
  102. uint32_t tud_cdc_n_available(uint8_t itf)
  103. {
  104. return tu_fifo_count(&_cdcd_itf[itf].rx_ff);
  105. }
  106. char tud_cdc_n_read_char(uint8_t itf)
  107. {
  108. char ch;
  109. return tud_cdc_n_read(itf, &ch, 1) ? ch : (-1);
  110. }
  111. uint32_t tud_cdc_n_read(uint8_t itf, void* buffer, uint32_t bufsize)
  112. {
  113. uint32_t num_read = tu_fifo_read_n(&_cdcd_itf[itf].rx_ff, buffer, bufsize);
  114. _prep_out_transaction(itf);
  115. return num_read;
  116. }
  117. char tud_cdc_n_peek(uint8_t itf, int pos)
  118. {
  119. char ch;
  120. return tu_fifo_peek_at(&_cdcd_itf[itf].rx_ff, pos, &ch) ? ch : (-1);
  121. }
  122. void tud_cdc_n_read_flush (uint8_t itf)
  123. {
  124. tu_fifo_clear(&_cdcd_itf[itf].rx_ff);
  125. _prep_out_transaction(itf);
  126. }
  127. //--------------------------------------------------------------------+
  128. // WRITE API
  129. //--------------------------------------------------------------------+
  130. uint32_t tud_cdc_n_write_char(uint8_t itf, char ch)
  131. {
  132. return tud_cdc_n_write(itf, &ch, 1);
  133. }
  134. uint32_t tud_cdc_n_write_str (uint8_t itf, char const* str)
  135. {
  136. return tud_cdc_n_write(itf, str, strlen(str));
  137. }
  138. uint32_t tud_cdc_n_write(uint8_t itf, void const* buffer, uint32_t bufsize)
  139. {
  140. uint16_t ret = tu_fifo_write_n(&_cdcd_itf[itf].tx_ff, buffer, bufsize);
  141. #if 0 // TODO issue with circuitpython's REPL
  142. // flush if queue more than endpoint size
  143. if ( tu_fifo_count(&_cdcd_itf[itf].tx_ff) >= CFG_TUD_CDC_EPSIZE )
  144. {
  145. tud_cdc_n_write_flush(itf);
  146. }
  147. #endif
  148. return ret;
  149. }
  150. bool tud_cdc_n_write_flush (uint8_t itf)
  151. {
  152. cdcd_interface_t* p_cdc = &_cdcd_itf[itf];
  153. TU_VERIFY( !dcd_edpt_busy(TUD_OPT_RHPORT, p_cdc->ep_in) ); // skip if previous transfer not complete
  154. uint16_t count = tu_fifo_read_n(&_cdcd_itf[itf].tx_ff, p_cdc->epin_buf, CFG_TUD_CDC_EPSIZE);
  155. if ( count )
  156. {
  157. TU_VERIFY( tud_cdc_n_connected(itf) ); // fifo is empty if not connected
  158. TU_ASSERT( dcd_edpt_xfer(TUD_OPT_RHPORT, p_cdc->ep_in, p_cdc->epin_buf, count) );
  159. }
  160. return true;
  161. }
  162. //--------------------------------------------------------------------+
  163. // USBD Driver API
  164. //--------------------------------------------------------------------+
  165. void cdcd_init(void)
  166. {
  167. tu_memclr(_cdcd_itf, sizeof(_cdcd_itf));
  168. for(uint8_t i=0; i<CFG_TUD_CDC; i++)
  169. {
  170. cdcd_interface_t* p_cdc = &_cdcd_itf[i];
  171. p_cdc->wanted_char = -1;
  172. // default line coding is : stop bit = 1, parity = none, data bits = 8
  173. p_cdc->line_coding.bit_rate = 115200;
  174. p_cdc->line_coding.stop_bits = 0;
  175. p_cdc->line_coding.parity = 0;
  176. p_cdc->line_coding.data_bits = 8;
  177. // config fifo
  178. tu_fifo_config(&p_cdc->rx_ff, p_cdc->rx_ff_buf, CFG_TUD_CDC_RX_BUFSIZE, 1, false);
  179. tu_fifo_config(&p_cdc->tx_ff, p_cdc->tx_ff_buf, CFG_TUD_CDC_TX_BUFSIZE, 1, false);
  180. #if CFG_FIFO_MUTEX
  181. tu_fifo_config_mutex(&p_cdc->rx_ff, osal_mutex_create(&p_cdc->rx_ff_mutex));
  182. tu_fifo_config_mutex(&p_cdc->tx_ff, osal_mutex_create(&p_cdc->tx_ff_mutex));
  183. #endif
  184. }
  185. }
  186. void cdcd_reset(uint8_t rhport)
  187. {
  188. (void) rhport;
  189. for(uint8_t i=0; i<CFG_TUD_CDC; i++)
  190. {
  191. tu_memclr(&_cdcd_itf[i], ITF_MEM_RESET_SIZE);
  192. tu_fifo_clear(&_cdcd_itf[i].rx_ff);
  193. tu_fifo_clear(&_cdcd_itf[i].tx_ff);
  194. }
  195. }
  196. bool cdcd_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t *p_length)
  197. {
  198. // Only support ACM subclass
  199. TU_ASSERT ( CDC_COMM_SUBCLASS_ABSTRACT_CONTROL_MODEL == itf_desc->bInterfaceSubClass);
  200. // Only support AT commands, no protocol and vendor specific commands.
  201. TU_ASSERT(tu_within(CDC_COMM_PROTOCOL_NONE, itf_desc->bInterfaceProtocol, CDC_COMM_PROTOCOL_ATCOMMAND_CDMA) ||
  202. itf_desc->bInterfaceProtocol == 0xff);
  203. // Find available interface
  204. cdcd_interface_t * p_cdc = NULL;
  205. uint8_t cdc_id;
  206. for(cdc_id=0; cdc_id<CFG_TUD_CDC; cdc_id++)
  207. {
  208. if ( _cdcd_itf[cdc_id].ep_in == 0 )
  209. {
  210. p_cdc = &_cdcd_itf[cdc_id];
  211. break;
  212. }
  213. }
  214. TU_ASSERT(p_cdc);
  215. //------------- Control Interface -------------//
  216. p_cdc->itf_num = itf_desc->bInterfaceNumber;
  217. uint8_t const * p_desc = tu_desc_next( itf_desc );
  218. (*p_length) = sizeof(tusb_desc_interface_t);
  219. // Communication Functional Descriptors
  220. while ( TUSB_DESC_CLASS_SPECIFIC == tu_desc_type(p_desc) )
  221. {
  222. (*p_length) += tu_desc_len(p_desc);
  223. p_desc = tu_desc_next(p_desc);
  224. }
  225. if ( TUSB_DESC_ENDPOINT == tu_desc_type(p_desc) )
  226. {
  227. // notification endpoint if any
  228. TU_ASSERT( dcd_edpt_open(rhport, (tusb_desc_endpoint_t const *) p_desc) );
  229. p_cdc->ep_notif = ((tusb_desc_endpoint_t const *) p_desc)->bEndpointAddress;
  230. (*p_length) += p_desc[DESC_OFFSET_LEN];
  231. p_desc = tu_desc_next(p_desc);
  232. }
  233. //------------- Data Interface (if any) -------------//
  234. if ( (TUSB_DESC_INTERFACE == p_desc[DESC_OFFSET_TYPE]) &&
  235. (TUSB_CLASS_CDC_DATA == ((tusb_desc_interface_t const *) p_desc)->bInterfaceClass) )
  236. {
  237. // next to endpoint descriptor
  238. p_desc = tu_desc_next(p_desc);
  239. // Open endpoint pair
  240. TU_ASSERT( usbd_open_edpt_pair(rhport, p_desc, 2, TUSB_XFER_BULK, &p_cdc->ep_out, &p_cdc->ep_in) );
  241. (*p_length) += sizeof(tusb_desc_interface_t) + 2*sizeof(tusb_desc_endpoint_t);
  242. }
  243. // Prepare for incoming data
  244. pending_read_from_host = false;
  245. _prep_out_transaction(cdc_id);
  246. return true;
  247. }
  248. // Invoked when class request DATA stage is finished.
  249. // return false to stall control endpoint (e.g Host send non-sense DATA)
  250. bool cdcd_control_request_complete(uint8_t rhport, tusb_control_request_t const * request)
  251. {
  252. (void) rhport;
  253. //------------- Class Specific Request -------------//
  254. TU_VERIFY (request->bmRequestType_bit.type == TUSB_REQ_TYPE_CLASS);
  255. // TODO Support multiple interfaces
  256. uint8_t const itf = 0;
  257. cdcd_interface_t* p_cdc = &_cdcd_itf[itf];
  258. // Invoke callback
  259. if ( CDC_REQUEST_SET_LINE_CODING == request->bRequest )
  260. {
  261. if ( tud_cdc_line_coding_cb ) tud_cdc_line_coding_cb(itf, &p_cdc->line_coding);
  262. }
  263. return true;
  264. }
  265. // Handle class control request
  266. // return false to stall control endpoint (e.g unsupported request)
  267. bool cdcd_control_request(uint8_t rhport, tusb_control_request_t const * request)
  268. {
  269. //------------- Class Specific Request -------------//
  270. TU_ASSERT(request->bmRequestType_bit.type == TUSB_REQ_TYPE_CLASS);
  271. // TODO Support multiple interfaces
  272. uint8_t const itf = 0;
  273. cdcd_interface_t* p_cdc = &_cdcd_itf[itf];
  274. switch ( request->bRequest )
  275. {
  276. case CDC_REQUEST_SET_LINE_CODING:
  277. usbd_control_xfer(rhport, request, &p_cdc->line_coding, sizeof(cdc_line_coding_t));
  278. break;
  279. case CDC_REQUEST_GET_LINE_CODING:
  280. usbd_control_xfer(rhport, request, &p_cdc->line_coding, sizeof(cdc_line_coding_t));
  281. break;
  282. case CDC_REQUEST_SET_CONTROL_LINE_STATE:
  283. // CDC PSTN v1.2 section 6.3.12
  284. // Bit 0: Indicates if DTE is present or not.
  285. // This signal corresponds to V.24 signal 108/2 and RS-232 signal DTR (Data Terminal Ready)
  286. // Bit 1: Carrier control for half-duplex modems.
  287. // This signal corresponds to V.24 signal 105 and RS-232 signal RTS (Request to Send)
  288. p_cdc->line_state = (uint8_t) request->wValue;
  289. usbd_control_status(rhport, request);
  290. // Invoke callback
  291. if ( tud_cdc_line_state_cb) tud_cdc_line_state_cb(itf, tu_bit_test(request->wValue, 0), tu_bit_test(request->wValue, 1));
  292. break;
  293. default: return false; // stall unsupported request
  294. }
  295. return true;
  296. }
  297. bool cdcd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes)
  298. {
  299. (void) rhport;
  300. (void) result;
  301. // TODO Support multiple interfaces
  302. uint8_t const itf = 0;
  303. cdcd_interface_t* p_cdc = &_cdcd_itf[itf];
  304. // receive new data
  305. if ( ep_addr == p_cdc->ep_out )
  306. {
  307. for(uint32_t i=0; i<xferred_bytes; i++)
  308. {
  309. tu_fifo_write(&p_cdc->rx_ff, &p_cdc->epout_buf[i]);
  310. // Check for wanted char and invoke callback if needed
  311. if ( tud_cdc_rx_wanted_cb && ( ((signed char) p_cdc->wanted_char) != -1 ) && ( p_cdc->wanted_char == p_cdc->epout_buf[i] ) )
  312. {
  313. tud_cdc_rx_wanted_cb(itf, p_cdc->wanted_char);
  314. }
  315. }
  316. // invoke receive callback (if there is still data)
  317. if (tud_cdc_rx_cb && tu_fifo_count(&p_cdc->rx_ff) ) tud_cdc_rx_cb(itf);
  318. // prepare for OUT transaction
  319. pending_read_from_host = false;
  320. _prep_out_transaction(itf);
  321. }
  322. // nothing to do with in and notif endpoint for now
  323. return true;
  324. }
  325. #endif