Table of Contents | ||||||
---|---|---|---|---|---|---|
|
...
The Vendor class offers the following functions to communicate with the host. For more details about the functions parameters, refer to the Vendor Class Functions reference.
Anchor | ||||
---|---|---|---|---|
|
Panel | ||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| ||||||||||||||||||
|
The vendor requests are also another way to communicate with the host. When managing vendor requests sent by the host, the application can receive or send data from or to the host using the control endpoint. For that, you will need to provide an application callback passed as a parameter of USBD_Vendor_Add
.
...
Synchronous communication means that the transfer is blocking. Upon function call, the application blocks until the transfer completes with or without an error. A timeout can be specified to avoid waiting forever.
presents Listing - Synchronous Bulk Read and Write Example presents a read and write example to receive data from the host using the bulk OUT endpoint and to send data to the host using the bulk IN endpoint.
Anchor | ||||
---|---|---|---|---|
|
Code Block | ||||||
---|---|---|---|---|---|---|
| ||||||
CPU_INT08U rx_buf[2];
CPU_INT08U tx_buf[2];
USBD_ERR err;
(void)USBD_Vendor_Rd( class_nbr, (1)
(void *)&rx_buf[0], (2)
2u,
0u, (3)
&err);
if (err != USBD_ERR_NONE) {
/* $$$$ Handle the error. */
}
(void)USBD_Vendor_Wr( class_nbr, (1)
(void *)&tx_buf[0], (4)
2u,
0u, (3)
DEF_FALSE, (5)
&err);
if (err != USBD_ERR_NONE) {
/* $$$$ Handle the error. */
} |
Panel | ||
---|---|---|
| ||
(1) The class instance number created with (2) The application must ensure that the buffer provided to the function is large enough to accommodate all the data. Otherwise, synchronization issues might happen. (3) In order to avoid an infinite blocking situation, a timeout expressed in milliseconds can be specified. A value of ‘0’ makes the application task wait forever. (4) The application provides the initialized transmit buffer. (5) If this flag is set to |
The use of interrupt endpoint communication functions, USBD_Vendor_IntrRd()
and USBD_Vendor_IntrWr()
, is similar to bulk endpoint communication functions presented in Listing - Synchronous Bulk Read and Write Example.
Asynchronous Communication
Asynchronous communication means that the transfer is non-blocking. Upon function call, the application passes the transfer information to the device stack and does not block. Other application processing can be done while the transfer is in progress over the USB bus. Once the transfer has completed, a callback function is called by the device stack to inform the application about the transfer completion. shows Listing - Asynchronous Bulk Read and Write Example shows an example of asynchronous read and write.
Anchor | ||||
---|---|---|---|---|
|
Code Block | ||||||
---|---|---|---|---|---|---|
| ||||||
void App_USBD_Vendor_Comm (CPU_INT08U class_nbr)
{
CPU_INT08U rx_buf[2];
CPU_INT08U tx_buf[2];
USBD_ERR err;
USBD_Vendor_RdAsync( class_nbr, (1)
(void *)&rx_buf[0], (2)
2u,
App_USBD_Vendor_RxCmpl, (3)
(void *) 0u, (4)
&err);
if (err != USBD_ERR_NONE) {
/* $$$$ Handle the error. */
}
USBD_Vendor_WrAsync( class_nbr, (1)
(void *)&tx_buf[0], (5)
2u,
App_USBD_Vendor_TxCmpl, (3)
(void *) 0u, (4)
DEF_FALSE, (6)
&err);
if (err != USBD_ERR_NONE) {
/* $$$$ Handle the error. */
}
}
static void App_USBD_Vendor_RxCmpl (CPU_INT08U class_nbr, (3)
void *p_buf,
CPU_INT32U buf_len,
CPU_INT32U xfer_len,
void *p_callback_arg,
USBD_ERR err)
{
(void)class_nbr;
(void)p_buf;
(void)buf_len;
(void)xfer_len;
(void)p_callback_arg; (4)
if (err == USBD_ERR_NONE) {
/* $$$$ Do some processing. */
} else {
/* $$$$ Handle the error. */
}
}
static void App_USBD_Vendor_TxCmpl (CPU_INT08U class_nbr, (3)
void *p_buf,
CPU_INT32U buf_len,
CPU_INT32U xfer_len,
void *p_callback_arg,
USBD_ERR err)
{
(void)class_nbr;
(void)p_buf;
(void)buf_len;
(void)xfer_len;
(void)p_callback_arg; (4)
if (err == USBD_ERR_NONE) {
/* $$$$ Do some processing. */
} else {
/* $$$$ Handle the error. */
}
} |
Panel | ||
---|---|---|
| ||
(1) The class instance number serves internally to the Vendor class to route the transfer to the proper bulk OUT or IN endpoint. (2) The application must ensure that the buffer provided is large enough to accommodate all the data. Otherwise, there may be synchronization issues. (3) The application provides a callback function pointer passed as a parameter. Upon completion of the transfer, the device stack calls this callback function so that the application can finalize the transfer by analyzing the transfer result. For instance, upon read operation completion, the application may do a certain processing with the received data. Upon write completion, the application may indicate if the write was successful and how many bytes were sent. (4) An argument associated to the callback can be also passed. Then in the callback context, some private information can be retrieved. (5) The application provides the initialized transmit buffer. (6) If this flag is set to |
The use of interrupt endpoint communication functions, USBD_Vendor_IntrRdAsync()
and USBD_Vendor_IntrWrAsync()
, is similar to bulk endpoint communication functions presented in Listing - Asynchronous Bulk Read and Write Example.
Vendor Request
The USB 2.0 specification defines three types of requests: standard, class and vendor. All standard requests are handled directly by the core layer. Any class request will be managed by the proper associated class. The vendor request may be processed by the vendor class. You must provide an application callback as a parameter of USBD_Vendor_Add
(as shown in Listing - Vendor Class Initialization Example) to be able to process one or more vendor requests. Once a vendor request is received by the USB device, it must be decoded properly. shows Listing - Example of Vendor Request Decoding shows an example of vendor request decoding. Certain request may require to receive or send from or to the host during the data stage of a control transfer. If no data stage is present, you just have to decode the Setup packet. This example shows the three types of data stage management: no data, data OUT and data IN.
Anchor | ||||
---|---|---|---|---|
|
Code Block | ||||||
---|---|---|---|---|---|---|
| ||||||
#define APP_VENDOR_REQ_NO_DATA 0x01u #define APP_VENDOR_REQ_RECEIVE_DATA_FROM_HOST 0x02u #define APP_VENDOR_REQ_SEND_DATA_TO_HOST 0x03u #define APP_VENDOR_REQ_DATA_BUF_SIZE 50u static CPU_INT08U AppVendorReqBuf[APP_VENDOR_REQ_DATA_BUF_SIZE]; static CPU_BOOLEAN App_USBD_Vendor_VendorReq ( CPU_INT08U class_nbr, CPU_INT08U dev_nbr, const USBD_SETUP_REQ *p_setup_req) (1) { CPU_BOOLEAN valid; USBD_ERR err_usb; CPU_INT16U req_len; (void)&class_nbr; switch(p_setup_req->bRequest) { (2) case APP_VENDOR_REQ_NO_DATA: (3) APP_TRACE_DBG(("Vendor request [0x%X]:\r\n", p_setup_req->bRequest)); APP_TRACE_DBG(("wIndex = %d\r\n", p_setup_req->wIndex)); APP_TRACE_DBG(("wLength = %d\r\n", p_setup_req->wLength)); APP_TRACE_DBG(("wValue = %d\r\n", p_setup_req->wValue)); valid = DEF_OK; break; case APP_VENDOR_REQ_RECEIVE_DATA_FROM_HOST: (4) req_len = p_setup_req->wLength; if (req_len > APP_VENDOR_REQ_DATA_BUF_SIZE) { return (DEF_FAIL); /* Not enough room to receive data. */ } APP_TRACE_DBG(("Vendor request [0x%X]:\r\n", p_setup_req->bRequest)); /* Receive data via Control OUT EP. */ (void)USBD_CtrlRx( dev_nbr, (void *)&AppVendorReqBuf[0u], req_len, 0u, /* Wait transfer completion forever. */ &err_usb); if (err_usb != USBD_ERR_NONE) { APP_TRACE_DBG(("Error receiving data from host: %d\r\n", err_usb)); valid = DEF_FAIL; } else { APP_TRACE_DBG(("wIndex = %d\r\n", p_setup_req->wIndex)); APP_TRACE_DBG(("wLength = %d\r\n", p_setup_req->wLength)); APP_TRACE_DBG(("wValue = %d\r\n", p_setup_req->wValue)); APP_TRACE_DBG(("Received %d octets from host via Control EP OUT\r\n", req_len)); valid = DEF_OK; } break; case APP_VENDOR_REQ_SEND_DATA_TO_HOST: (5) APP_TRACE_DBG(("Vendor request [0x%X]:\r\n", p_setup_req->bRequest)); req_len = APP_VENDOR_REQ_DATA_BUF_SIZE; Mem_Set((void *)&AppVendorReqBuf[0u], /* Fill buf with a pattern. */ 'A', req_len); /* Send data via Control IN EP. */ (void)USBD_CtrlTx( dev_nbr, (void *)&AppVendorReqBuf[0u], req_len, 0u, /* Wait transfer completion forever. */ DEF_NO, &err_usb); if (err_usb != USBD_ERR_NONE) { APP_TRACE_DBG(("Error sending data to host: %d\r\n", err_usb)); valid = DEF_FAIL; } else { APP_TRACE_DBG(("wIndex = %d\r\n", p_setup_req->wIndex)); APP_TRACE_DBG(("wLength = %d\r\n", p_setup_req->wLength)); APP_TRACE_DBG(("wValue = %d\r\n", p_setup_req->wValue)); APP_TRACE_DBG(("Sent %d octets to host via Control EP IN\r\n", req_len)); valid = DEF_OK; } break; default: (6) valid = DEF_FAIL; /* Request is not supported. */ break; } return (valid); } |
Panel | |||||||
---|---|---|---|---|---|---|---|
| |||||||
(1) The core will pass to your application the Setup packet content. The structure
(2) Determine the request. You may use a (3) If no data stage is present, you just need to decode the other fields. The presence of a data stage or not is indicated by the field (4) If the host sends data to the device, you must call the function (5) If the host receives data from the device, you must call the function (6) In this example, all requests not recognized are marked by returning |
The host sends vendor requests using the function USBDev_CtrlReq()
. Refer to the page USBDev_API for more details about how to send vendor requests on the host side.
...