Просмотр исходного кода

cdc host, add set line coding API

hathach 3 лет назад
Родитель
Сommit
05c119ce97
4 измененных файлов с 143 добавлено и 41 удалено
  1. 9 2
      examples/host/cdc_msc_hid/src/tusb_config.h
  2. 22 6
      src/class/cdc/cdc.h
  3. 100 29
      src/class/cdc/cdc_host.c
  4. 12 4
      src/class/cdc/cdc_host.h

+ 9 - 2
examples/host/cdc_msc_hid/src/tusb_config.h

@@ -109,8 +109,15 @@
 #define CFG_TUH_HID_EPOUT_BUFSIZE   64
 
 //------------- CDC -------------//
-// Set both DTR ( bit 0), RTS (bit 1) on enumeration/mounted
-#define CFG_TUH_CDC_SET_DTRRTS_ON_ENUM    0x03
+
+// Set Line Control state on enumeration/mounted:
+// DTR ( bit 0), RTS (bit 1)
+#define CFG_TUH_CDC_LINE_CONTROL_ON_ENUM    0x03
+
+// Set Line Coding on enumeration/mounted, value for cdc_line_coding_t
+// bit rate = 115200, 1 stop bit, no parity, 8 bit data width
+#define CFG_TUH_CDC_LINE_CODING_ON_ENUM   { 115200, CDC_LINE_CONDING_STOP_BITS_1, CDC_LINE_CODING_PARITY_NONE, 8 }
+
 
 #ifdef __cplusplus
  }

+ 22 - 6
src/class/cdc/cdc.h

@@ -198,6 +198,22 @@ enum
   CDC_CONTROL_LINE_STATE_RTS = 0x02,
 };
 
+enum
+{
+  CDC_LINE_CONDING_STOP_BITS_1   = 0, // 1   bit
+  CDC_LINE_CONDING_STOP_BITS_1_5 = 1, // 1.5 bits
+  CDC_LINE_CONDING_STOP_BITS_2   = 2, // 2   bits
+};
+
+enum
+{
+  CDC_LINE_CODING_PARITY_NONE  = 0,
+  CDC_LINE_CODING_PARITY_ODD   = 1,
+  CDC_LINE_CODING_PARITY_EVEN  = 2,
+  CDC_LINE_CODING_PARITY_MARK  = 3,
+  CDC_LINE_CODING_PARITY_SPACE = 4,
+};
+
 //--------------------------------------------------------------------+
 // Management Element Notification (Notification Endpoint)
 //--------------------------------------------------------------------+
@@ -207,13 +223,13 @@ typedef enum
 {
   CDC_NOTIF_NETWORK_CONNECTION               = 0x00, ///< This notification allows the device to notify the host about network connection status.
   CDC_NOTIF_RESPONSE_AVAILABLE               = 0x01, ///< This notification allows the device to notify the hostthat a response is available. This response can be retrieved with a subsequent \ref CDC_REQUEST_GET_ENCAPSULATED_RESPONSE request.
-  CDC_NOTIF_AUX_JACK_HOOK_STATE              = 0x08,
-  CDC_NOTIF_RING_DETECT                      = 0x09,
-  CDC_NOTIF_SERIAL_STATE                     = 0x20,
-  CDC_NOTIF_CALL_STATE_CHANGE                = 0x28,
-  CDC_NOTIF_LINE_STATE_CHANGE                = 0x29,
+  CDC_NOTIF_AUX_JACK_HOOK_STATE              = 0x08,///< CDC_NOTIF_AUX_JACK_HOOK_STATE
+  CDC_NOTIF_RING_DETECT                      = 0x09,///< CDC_NOTIF_RING_DETECT
+  CDC_NOTIF_SERIAL_STATE                     = 0x20,///< CDC_NOTIF_SERIAL_STATE
+  CDC_NOTIF_CALL_STATE_CHANGE                = 0x28,///< CDC_NOTIF_CALL_STATE_CHANGE
+  CDC_NOTIF_LINE_STATE_CHANGE                = 0x29,///< CDC_NOTIF_LINE_STATE_CHANGE
   CDC_NOTIF_CONNECTION_SPEED_CHANGE          = 0x2A, ///< This notification allows the device to inform the host-networking driver that a change in either the upstream or the downstream bit rate of the connection has occurred
-  CDC_NOTIF_MDLM_SEMANTIC_MODEL_NOTIFICATION = 0x40,
+  CDC_NOTIF_MDLM_SEMANTIC_MODEL_NOTIFICATION = 0x40,///< CDC_NOTIF_MDLM_SEMANTIC_MODEL_NOTIFICATION
 }cdc_notification_request_t;
 
 //--------------------------------------------------------------------+

+ 100 - 29
src/class/cdc/cdc_host.c

@@ -52,8 +52,8 @@ typedef struct {
   cdc_acm_capability_t acm_capability;
   uint8_t ep_notif;
 
-  // Bit 0:  DTR (Data Terminal Ready), Bit 1: RTS (Request to Send)
-  uint8_t line_state;
+  cdc_line_coding_t line_coding; // Baudrate, stop bits, parity, data width
+  uint8_t line_state; // DTR (bit0), RTS (bit1)
 
   tuh_xfer_cb_t user_control_cb;
 
@@ -240,6 +240,13 @@ static void cdch_internal_control_complete(tuh_xfer_t* xfer)
         p_cdc->line_state = (uint8_t) tu_le16toh(xfer->setup->wValue);
       break;
 
+      case CDC_REQUEST_SET_LINE_CODING:
+      {
+        uint16_t const len = tu_min16(sizeof(cdc_line_coding_t), tu_le16toh(xfer->setup->wLength));
+        memcpy(&p_cdc->line_coding, xfer->buffer, len);
+      }
+      break;
+
       default: break;
     }
   }
@@ -265,7 +272,7 @@ bool tuh_cdc_set_control_line_state(uint8_t idx, uint16_t line_state, tuh_xfer_c
     },
     .bRequest = CDC_REQUEST_SET_CONTROL_LINE_STATE,
     .wValue   = tu_htole16(line_state),
-    .wIndex   = tu_htole16(p_cdc->bInterfaceNumber),
+    .wIndex   = tu_htole16((uint16_t) p_cdc->bInterfaceNumber),
     .wLength  = 0
   };
 
@@ -283,6 +290,46 @@ bool tuh_cdc_set_control_line_state(uint8_t idx, uint16_t line_state, tuh_xfer_c
   return tuh_control_xfer(&xfer);
 }
 
+bool tuh_cdc_set_line_coding(uint8_t idx, cdc_line_coding_t const* line_coding, tuh_xfer_cb_t complete_cb, uintptr_t user_data)
+{
+  cdch_interface_t* p_cdc = get_itf(idx);
+  TU_VERIFY(p_cdc && p_cdc->acm_capability.support_line_request);
+
+  TU_LOG_CDCH("CDC Set Line Conding\r\n");
+
+  tusb_control_request_t const request =
+  {
+    .bmRequestType_bit =
+    {
+      .recipient = TUSB_REQ_RCPT_INTERFACE,
+      .type      = TUSB_REQ_TYPE_CLASS,
+      .direction = TUSB_DIR_OUT
+    },
+    .bRequest = CDC_REQUEST_SET_LINE_CODING,
+    .wValue   = 0,
+    .wIndex   = tu_htole16(p_cdc->bInterfaceNumber),
+    .wLength  = tu_htole16(sizeof(cdc_line_coding_t))
+  };
+
+  // use usbh enum buf to hold line coding since user line_coding variable may not live long enough
+  // for the transfer to complete
+  uint8_t* enum_buf = usbh_get_enum_buf();
+  memcpy(enum_buf, line_coding, sizeof(cdc_line_coding_t));
+
+  p_cdc->user_control_cb = complete_cb;
+  tuh_xfer_t xfer =
+  {
+    .daddr       = p_cdc->daddr,
+    .ep_addr     = 0,
+    .setup       = &request,
+    .buffer      = enum_buf,
+    .complete_cb = cdch_internal_control_complete,
+    .user_data   = user_data
+  };
+
+  return tuh_control_xfer(&xfer);
+}
+
 //--------------------------------------------------------------------+
 // CLASS-USBH API
 //--------------------------------------------------------------------+
@@ -448,46 +495,70 @@ bool cdch_open(uint8_t rhport, uint8_t daddr, tusb_desc_interface_t const *itf_d
   return true;
 }
 
-static void config_cdc_complete(uint8_t daddr, uint8_t itf_num)
+enum
 {
-  uint8_t const idx = tuh_cdc_itf_get_index(daddr, itf_num);
+  CONFIG_SET_CONTROL_LINE_STATE,
+  CONFIG_SET_LINE_CODING,
+  CONFIG_COMPLETE
+};
 
-  if (idx != TUSB_INDEX_INVALID)
+static void process_cdc_config(tuh_xfer_t* xfer)
+{
+  uintptr_t const state = xfer->user_data;
+  uint8_t const itf_num = (uint8_t) tu_le16toh(xfer->setup->wIndex);
+  uint8_t const idx = tuh_cdc_itf_get_index(xfer->daddr, itf_num);
+  TU_ASSERT(idx != TUSB_INDEX_INVALID, );
+
+  switch(state)
   {
-    if (tuh_cdc_mount_cb) tuh_cdc_mount_cb(idx);
+    case CONFIG_SET_CONTROL_LINE_STATE:
+    #if CFG_TUH_CDC_LINE_CONTROL_ON_ENUM
+      TU_ASSERT( tuh_cdc_set_control_line_state(idx, CFG_TUH_CDC_LINE_CONTROL_ON_ENUM, process_cdc_config, CONFIG_SET_LINE_CODING), );
+      break;
+    #endif
+    TU_ATTR_FALLTHROUGH;
 
-    // Prepare for incoming data
-    cdch_interface_t* p_cdc = get_itf(idx);
-    tu_edpt_stream_read_xfer(&p_cdc->stream.rx);
-  }
+    case CONFIG_SET_LINE_CODING:
+    #ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM
+    {
+      cdc_line_coding_t line_coding = CFG_TUH_CDC_LINE_CODING_ON_ENUM;
+      TU_ASSERT( tuh_cdc_set_line_coding(idx, &line_coding, process_cdc_config, 0), );
+      break;
+    }
+    #endif
+    TU_ATTR_FALLTHROUGH;
 
-  // notify usbh that driver enumeration is complete
-  // itf_num+1 to account for data interface as well
-  usbh_driver_set_config_complete(daddr, itf_num+1);
-}
+    case CONFIG_COMPLETE:
+      if (tuh_cdc_mount_cb) tuh_cdc_mount_cb(idx);
 
-#if CFG_TUH_CDC_SET_DTRRTS_ON_ENUM
+      // Prepare for incoming data
+      cdch_interface_t* p_cdc = get_itf(idx);
+      tu_edpt_stream_read_xfer(&p_cdc->stream.rx);
 
-static void config_set_dtr_rts_complete (tuh_xfer_t* xfer)
-{
-  uint8_t const itf_num = (uint8_t) tu_le16toh(xfer->setup->wIndex);
-  config_cdc_complete(xfer->daddr, itf_num);
+      // notify usbh that driver enumeration is complete
+      // itf_num+1 to account for data interface as well
+      usbh_driver_set_config_complete(xfer->daddr, itf_num+1);
+    break;
+
+    default: break;
+  }
 }
 
 bool cdch_set_config(uint8_t daddr, uint8_t itf_num)
 {
-  uint8_t const idx = tuh_cdc_itf_get_index(daddr, itf_num);
-  return tuh_cdc_set_control_line_state(idx, CFG_TUH_CDC_SET_DTRRTS_ON_ENUM, config_set_dtr_rts_complete, 0);
-}
+  // fake transfer to kick-off process
+  tusb_control_request_t request;
+  request.wIndex = tu_htole16((uint16_t) itf_num);
 
-#else
+  tuh_xfer_t xfer;
+  xfer.daddr     = daddr;
+  xfer.result    = XFER_RESULT_SUCCESS;
+  xfer.setup     = &request;
+  xfer.user_data = CONFIG_SET_CONTROL_LINE_STATE;
+
+  process_cdc_config(&xfer);
 
-bool cdch_set_config(uint8_t daddr, uint8_t itf_num)
-{
-  config_cdc_complete(daddr, itf_num);
   return true;
 }
 
 #endif
-
-#endif

+ 12 - 4
src/class/cdc/cdc_host.h

@@ -37,11 +37,16 @@
 // Class Driver Configuration
 //--------------------------------------------------------------------+
 
-// Set DTR ( bit 0), RTS (bit 1) on enumeration/mounted
-#ifndef CFG_TUH_CDC_SET_DTRRTS_ON_ENUM
-#define CFG_TUH_CDC_SET_DTRRTS_ON_ENUM    0
+// Set Line Control state on enumeration/mounted: DTR ( bit 0), RTS (bit 1)
+#ifndef CFG_TUH_CDC_LINE_CONTROL_ON_ENUM
+#define CFG_TUH_CDC_LINE_CONTROL_ON_ENUM    0
 #endif
 
+// Set Line Coding on enumeration/mounted, value for cdc_line_coding_t
+//#ifndef CFG_TUH_CDC_LINE_CODING_ON_ENUM
+//#define CFG_TUH_CDC_LINE_CODING_ON_ENUM   { 115200, CDC_LINE_CONDING_STOP_BITS_1, CDC_LINE_CODING_PARITY_NONE, 8 }
+//#endif
+
 // RX FIFO size
 #ifndef CFG_TUH_CDC_RX_BUFSIZE
 #define CFG_TUH_CDC_RX_BUFSIZE USBH_EPSIZE_BULK_MAX
@@ -130,9 +135,12 @@ bool tuh_cdc_read_clear (uint8_t idx);
 // Control Endpoint (Request) API
 //--------------------------------------------------------------------+
 
-// Send control request to Set Control Line State: DTR (bit 0), RTS (bit 1)
+// Request to Set Control Line State: DTR (bit 0), RTS (bit 1)
 bool tuh_cdc_set_control_line_state(uint8_t idx, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data);
 
+// Request to Set Line Coding
+bool tuh_cdc_set_line_coding(uint8_t idx, cdc_line_coding_t const* line_coding, tuh_xfer_cb_t complete_cb, uintptr_t user_data);
+
 // Connect by set both DTR, RTS
 static inline bool tuh_cdc_connect(uint8_t idx, tuh_xfer_cb_t complete_cb, uintptr_t user_data)
 {