mirror of
https://github.com/espressif/esp-idf.git
synced 2025-08-01 19:54:32 +02:00
tinyusb: Add fix for tinyusb reading
Closes IDF-2029
This commit is contained in:
@@ -42,9 +42,9 @@ extern "C" {
|
|||||||
# endif
|
# endif
|
||||||
|
|
||||||
# if CFG_TUD_CDC
|
# if CFG_TUD_CDC
|
||||||
# if (CFG_TUD_CDC_EPSIZE < 4)
|
# if (CFG_TUD_CDC_EP_BUFSIZE < 4)
|
||||||
# define CFG_TUD_CDC_EPSIZE 4
|
# define CFG_TUD_CDC_EP_BUFSIZE 4
|
||||||
# warning "CFG_TUD_CDC_EPSIZE was too low and was set to 4"
|
# warning "CFG_TUD_CDC_EP_BUFSIZE was too low and was set to 4"
|
||||||
# endif
|
# endif
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
|
@@ -160,7 +160,12 @@ size_t tinyusb_cdcacm_write_queue_char(tinyusb_cdcacm_itf_t itf, char ch);
|
|||||||
size_t tinyusb_cdcacm_write_queue(tinyusb_cdcacm_itf_t itf, uint8_t *in_buf, size_t in_size);
|
size_t tinyusb_cdcacm_write_queue(tinyusb_cdcacm_itf_t itf, uint8_t *in_buf, size_t in_size);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Send all data from a write buffer. Use `tinyusb_cdcacm_write_queue` to add data to the buffer
|
* @brief Send all data from a write buffer. Use `tinyusb_cdcacm_write_queue` to add data to the buffer.
|
||||||
|
*
|
||||||
|
* WARNING! TinyUSB can block output Endpoint for several RX callbacks, after will do additional flush
|
||||||
|
* after the each trasfer. That can leads to the situation when you requested a flush, but it will fail until
|
||||||
|
* ont of the next callbacks ends.
|
||||||
|
* SO USING OF THE FLUSH WITH TIMEOUTS IN CALLBACKS IS NOT RECOMENDED - YOU CAN GET A LOCK FOR THE TIMEOUT
|
||||||
*
|
*
|
||||||
* @param itf - number of a CDC object
|
* @param itf - number of a CDC object
|
||||||
* @param timeout_ticks - waiting until flush will be considered as failed
|
* @param timeout_ticks - waiting until flush will be considered as failed
|
||||||
|
@@ -31,6 +31,7 @@ typedef struct {
|
|||||||
bool initialized;
|
bool initialized;
|
||||||
size_t rx_unread_buf_sz;
|
size_t rx_unread_buf_sz;
|
||||||
RingbufHandle_t rx_unread_buf;
|
RingbufHandle_t rx_unread_buf;
|
||||||
|
xSemaphoreHandle ringbuf_read_mux;
|
||||||
uint8_t *rx_tfbuf;
|
uint8_t *rx_tfbuf;
|
||||||
tusb_cdcacm_callback_t callback_rx;
|
tusb_cdcacm_callback_t callback_rx;
|
||||||
tusb_cdcacm_callback_t callback_rx_wanted_char;
|
tusb_cdcacm_callback_t callback_rx_wanted_char;
|
||||||
@@ -226,6 +227,35 @@ esp_err_t tinyusb_cdcacm_unregister_callback(tinyusb_cdcacm_itf_t itf,
|
|||||||
/*********************************************************************** TinyUSB callbacks*/
|
/*********************************************************************** TinyUSB callbacks*/
|
||||||
/* CDC-ACM
|
/* CDC-ACM
|
||||||
********************************************************************* */
|
********************************************************************* */
|
||||||
|
|
||||||
|
static esp_err_t read_from_rx_unread_to_buffer(esp_tusb_cdcacm_t *acm, uint8_t *out_buf, size_t req_bytes, size_t *read_bytes)
|
||||||
|
{
|
||||||
|
uint8_t *buf = xRingbufferReceiveUpTo(acm->rx_unread_buf, read_bytes, 0, req_bytes);
|
||||||
|
if (buf) {
|
||||||
|
memcpy(out_buf, buf, *read_bytes);
|
||||||
|
vRingbufferReturnItem(acm->rx_unread_buf, (void *)(buf));
|
||||||
|
return ESP_OK;
|
||||||
|
} else {
|
||||||
|
return ESP_ERR_NO_MEM;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static esp_err_t ringbuf_mux_take(esp_tusb_cdcacm_t *acm){
|
||||||
|
if(xSemaphoreTake(acm->ringbuf_read_mux, 0) != pdTRUE){
|
||||||
|
ESP_LOGW(TAG, "Read error: ACM is busy");
|
||||||
|
return ESP_ERR_INVALID_STATE;
|
||||||
|
}
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static esp_err_t ringbuf_mux_give(esp_tusb_cdcacm_t *acm){
|
||||||
|
if(xSemaphoreGive(acm->ringbuf_read_mux) != pdTRUE){
|
||||||
|
ESP_LOGW(TAG, "Can't return the ringbuff mutex: mutex hasn't been taken");
|
||||||
|
return ESP_ERR_INVALID_STATE;
|
||||||
|
}
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
esp_err_t tinyusb_cdcacm_read(tinyusb_cdcacm_itf_t itf, uint8_t *out_buf, size_t out_buf_sz, size_t *rx_data_size)
|
esp_err_t tinyusb_cdcacm_read(tinyusb_cdcacm_itf_t itf, uint8_t *out_buf, size_t out_buf_sz, size_t *rx_data_size)
|
||||||
{
|
{
|
||||||
esp_tusb_cdcacm_t *acm = get_acm(itf);
|
esp_tusb_cdcacm_t *acm = get_acm(itf);
|
||||||
@@ -233,15 +263,26 @@ esp_err_t tinyusb_cdcacm_read(tinyusb_cdcacm_itf_t itf, uint8_t *out_buf, size_t
|
|||||||
ESP_LOGE(TAG, "Interface is not initialized. Use `tinyusb_cdc_init` for initialization");
|
ESP_LOGE(TAG, "Interface is not initialized. Use `tinyusb_cdc_init` for initialization");
|
||||||
return ESP_ERR_INVALID_STATE;
|
return ESP_ERR_INVALID_STATE;
|
||||||
}
|
}
|
||||||
uint8_t *buf = xRingbufferReceiveUpTo(acm->rx_unread_buf, rx_data_size, 0, out_buf_sz);
|
size_t read_sz;
|
||||||
if (buf) {
|
|
||||||
memcpy(out_buf, buf, *rx_data_size);
|
/* Take a mutex to proceed two uninterrupted read operations */
|
||||||
vRingbufferReturnItem(acm->rx_unread_buf, (void *)buf);
|
ESP_RETURN_ON_ERROR(ringbuf_mux_take(acm));
|
||||||
return ESP_OK;
|
|
||||||
} else {
|
esp_err_t res = read_from_rx_unread_to_buffer(acm, out_buf, out_buf_sz, &read_sz);
|
||||||
ESP_LOGE(TAG, "Failed to receive item");
|
if (res != ESP_OK){
|
||||||
return ESP_ERR_NO_MEM;
|
ESP_RETURN_ON_ERROR(ringbuf_mux_give(acm));
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
*rx_data_size = read_sz;
|
||||||
|
/* Buffer's data can be wrapped, at that situations we should make another retrievement */
|
||||||
|
if (read_from_rx_unread_to_buffer(acm, out_buf+read_sz, out_buf_sz-read_sz, &read_sz) == ESP_OK) {
|
||||||
|
ESP_LOGV(TAG, "Buffer was wrapped, data obtained using two read operations.");
|
||||||
|
*rx_data_size += read_sz;
|
||||||
|
}
|
||||||
|
|
||||||
|
ESP_RETURN_ON_ERROR(ringbuf_mux_give(acm));
|
||||||
|
return ESP_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -262,7 +303,9 @@ size_t tinyusb_cdcacm_write_queue(tinyusb_cdcacm_itf_t itf, uint8_t *in_buf, siz
|
|||||||
return tud_cdc_n_write(itf, in_buf, in_size);
|
return tud_cdc_n_write(itf, in_buf, in_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static uint32_t tud_cdc_n_write_occupied(tinyusb_cdcacm_itf_t itf){
|
||||||
|
return CFG_TUD_CDC_TX_BUFSIZE - tud_cdc_n_write_available(itf);
|
||||||
|
}
|
||||||
|
|
||||||
esp_err_t tinyusb_cdcacm_write_flush(tinyusb_cdcacm_itf_t itf, uint32_t timeout_ticks)
|
esp_err_t tinyusb_cdcacm_write_flush(tinyusb_cdcacm_itf_t itf, uint32_t timeout_ticks)
|
||||||
{
|
{
|
||||||
@@ -273,9 +316,11 @@ esp_err_t tinyusb_cdcacm_write_flush(tinyusb_cdcacm_itf_t itf, uint32_t timeout_
|
|||||||
if (!timeout_ticks) { // if no timeout - nonblocking mode
|
if (!timeout_ticks) { // if no timeout - nonblocking mode
|
||||||
int res = tud_cdc_n_write_flush(itf);
|
int res = tud_cdc_n_write_flush(itf);
|
||||||
if (!res) {
|
if (!res) {
|
||||||
|
ESP_LOGW(TAG, "flush fauled (res: %d)", res);
|
||||||
return ESP_FAIL;
|
return ESP_FAIL;
|
||||||
} else {
|
} else {
|
||||||
if (tud_cdc_n_write_available(itf)) {
|
if (tud_cdc_n_write_occupied(itf)) {
|
||||||
|
ESP_LOGW(TAG, "remained data to flush!");
|
||||||
return ESP_FAIL;
|
return ESP_FAIL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -285,7 +330,7 @@ esp_err_t tinyusb_cdcacm_write_flush(tinyusb_cdcacm_itf_t itf, uint32_t timeout_
|
|||||||
uint32_t ticks_now = ticks_start;
|
uint32_t ticks_now = ticks_start;
|
||||||
while (1) { // loop until success or until the time runs out
|
while (1) { // loop until success or until the time runs out
|
||||||
ticks_now = xTaskGetTickCount();
|
ticks_now = xTaskGetTickCount();
|
||||||
if (!tud_cdc_n_write_available(itf)) { // if nothing to write - nothing to flush
|
if (!tud_cdc_n_write_occupied(itf)) { // if nothing to write - nothing to flush
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (tud_cdc_n_write_flush(itf)) { // Success
|
if (tud_cdc_n_write_flush(itf)) { // Success
|
||||||
@@ -347,6 +392,14 @@ esp_err_t tusb_cdc_acm_init(const tinyusb_config_cdcacm_t *cfg)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Buffers */
|
/* Buffers */
|
||||||
|
|
||||||
|
acm->ringbuf_read_mux = xSemaphoreCreateMutex();
|
||||||
|
if (acm->ringbuf_read_mux == NULL){
|
||||||
|
ESP_LOGE(TAG, "Creation of a ringbuf mutex failed");
|
||||||
|
free_obj(itf);
|
||||||
|
return ESP_ERR_NO_MEM;
|
||||||
|
}
|
||||||
|
|
||||||
acm->rx_tfbuf = malloc(CONFIG_USB_CDC_RX_BUFSIZE);
|
acm->rx_tfbuf = malloc(CONFIG_USB_CDC_RX_BUFSIZE);
|
||||||
if (!acm->rx_tfbuf) {
|
if (!acm->rx_tfbuf) {
|
||||||
ESP_LOGE(TAG, "Creation buffer error");
|
ESP_LOGE(TAG, "Creation buffer error");
|
||||||
|
@@ -153,7 +153,7 @@ static ssize_t tusb_write(int fd, const void *data, size_t size)
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
tinyusb_cdcacm_write_flush(s_vfstusb.cdc_intf, 0);
|
tud_cdc_n_write_flush(s_vfstusb.cdc_intf);
|
||||||
_lock_release(&(s_vfstusb.write_lock));
|
_lock_release(&(s_vfstusb.write_lock));
|
||||||
return written_sz;
|
return written_sz;
|
||||||
}
|
}
|
||||||
|
Submodule components/tinyusb/tinyusb updated: a2ba3dcccc...6d66d6bb21
@@ -38,7 +38,7 @@ void tinyusb_cdc_rx_callback(int itf, cdcacm_event_t *event)
|
|||||||
|
|
||||||
/* write back */
|
/* write back */
|
||||||
tinyusb_cdcacm_write_queue(itf, buf, rx_size);
|
tinyusb_cdcacm_write_queue(itf, buf, rx_size);
|
||||||
tinyusb_cdcacm_write_flush(itf, portMAX_DELAY);
|
tinyusb_cdcacm_write_flush(itf, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void tinyusb_cdc_line_state_changed_callback(int itf, cdcacm_event_t *event)
|
void tinyusb_cdc_line_state_changed_callback(int itf, cdcacm_event_t *event)
|
||||||
|
Reference in New Issue
Block a user