espressif_idf-extra-components/usb/usb_host_vcp/usb_host_vcp.cpp

92 lines
3.3 KiB
C++

/*
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdexcept>
#include "usb/vcp.hpp"
#include "esp_log.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
static const char *TAG = "VCP service";
namespace esp_usb {
std::vector<VCP::vcp_driver> VCP::drivers;
CdcAcmDevice *VCP::open(uint16_t _vid, uint16_t _pid, const cdc_acm_host_device_config_t *dev_config, uint8_t interface_idx)
{
// In case user didn't install CDC-ACM driver, we try to install it here.
const esp_err_t err = cdc_acm_host_install(NULL);
switch (err) {
case ESP_OK: ESP_LOGD(TAG, "CDC-ACM driver installed"); break;
case ESP_ERR_INVALID_STATE: ESP_LOGD(TAG, "CDC-ACM driver already installed"); break;
default: ESP_LOGE(TAG, "Failed to install CDC-ACM driver"); return nullptr;
}
for (vcp_driver drv : drivers) {
if (drv.vid == _vid) {
for (uint16_t p : drv.pids) {
if (p == _pid) {
try {
return drv.open(_pid, dev_config, interface_idx);
} catch (esp_err_t &e) {
switch (e) {
case ESP_ERR_NO_MEM: throw std::bad_alloc();
case ESP_ERR_NOT_FOUND: // fallthrough
default: return nullptr;
}
}
}
}
}
}
return nullptr;
}
CdcAcmDevice *VCP::open(const cdc_acm_host_device_config_t *dev_config, uint8_t interface_idx)
{
// Setup this function timeout
TickType_t timeout_ticks = (dev_config->connection_timeout_ms == 0) ? portMAX_DELAY : pdMS_TO_TICKS(dev_config->connection_timeout_ms);
TimeOut_t connection_timeout;
vTaskSetTimeOutState(&connection_timeout);
// In case user didn't install CDC-ACM driver, we try to install it here.
esp_err_t err = cdc_acm_host_install(NULL);
switch (err) {
case ESP_OK: ESP_LOGD(TAG, "CDC-ACM driver installed"); break;
case ESP_ERR_INVALID_STATE: ESP_LOGD(TAG, "CDC-ACM driver already installed"); break;
default: ESP_LOGE(TAG, "Failed to install CDC-ACM driver"); return nullptr;
}
// dev_config->connection_timeout_ms is normally meant for 1 device,
// but here it is a timeout for the whole function call
cdc_acm_host_device_config_t _config = {
.connection_timeout_ms = 1,
.out_buffer_size = dev_config->out_buffer_size,
.event_cb = dev_config->event_cb,
.data_cb = dev_config->data_cb,
.user_arg = dev_config->user_arg,
};
// Try opening all registered devices, return on first success
do {
for (vcp_driver drv : drivers) {
for (uint16_t pid : drv.pids) {
try {
return drv.open(pid, &_config, interface_idx);
} catch (esp_err_t &e) {
switch (e) {
case ESP_ERR_NOT_FOUND: break;
case ESP_ERR_NO_MEM: throw std::bad_alloc();
default: return nullptr;
}
}
}
}
vTaskDelay(pdMS_TO_TICKS(50));
} while (xTaskCheckForTimeOut(&connection_timeout, &timeout_ticks) == pdFALSE);
return nullptr;
}
} // namespace esp_usb