Closed marchingband closed 1 year ago
I see in the example code:
if (driver_obj.actions == 0) {
usb_host_client_handle_events(driver_obj.client_hdl, portMAX_DELAY);
} else {
... we handle events
}
but in yours:
usb_host_client_handle_events(driver_obj.client_hdl, 10);
... we handle events
Perhaps this leaves the driver in an invalid state such that it cannot be deregistered / uninstalled?
running the example code from esp-idf, when I unplug a device I get:
E (259720) USBH: Device 1 gone
I (259720) CLASS: Deregistering Client
I (259720) DAEMON: No more clients and devices
So the daemon task is seeing that the client is gone and can close well, which does not happen in yours, this 3rd log never occurs.
I see you replaced driver_obj->actions &= ~ACTION_GET_STR_DESC;
in the get_string_descriptor callback with a loop counter.
I wonder if you could help me understand why this is setup the way it is. I would love to help get this running as a pluggable driver. I believe yours is the only example of usb midi host online, so it's possible yours is the only esp32s3 midi usb host in the world :)
Ok I have fixed it but there are some major changes, l'll outline them here, just let me know if you'd like a PR, or if you want to discuss, or if you don't care that's totally understandable too, I realize that your device works perfectly just crashing and starting from the beginning. I will leave some code here to help anyone else who may end up here.
aciton_close_dev()
deletes some info that is needed to close the host, so I don't call that, instead, when the callback receives ACTION_CLOSE_DEV
, just break
if (driver_obj.actions & ACTION_CLOSE_DEV) {
// aciton_close_dev(&driver_obj);
break;
}
and then here is the closing code which I add at the end of class_driver_task()
// Cancel polling of BULK IN and OUT endpoints
transfer->callback = NULL;
in_transfer->callback = NULL;
// Reset the endpoints
ESP_ERROR_CHECK(usb_host_endpoint_halt(driver_obj.dev_hdl, transfer->bEndpointAddress));
ESP_ERROR_CHECK(usb_host_endpoint_flush(driver_obj.dev_hdl, transfer->bEndpointAddress));
ESP_ERROR_CHECK(usb_host_endpoint_halt(driver_obj.dev_hdl, in_transfer->bEndpointAddress));
ESP_ERROR_CHECK(usb_host_endpoint_flush(driver_obj.dev_hdl, in_transfer->bEndpointAddress));
ESP_LOGI(TAG, "Free transfers");
ESP_ERROR_CHECK(usb_host_transfer_free(transfer));
ESP_LOGI(TAG, "Free in_transfers");
ESP_ERROR_CHECK(usb_host_transfer_free(in_transfer));
// Release the host
ESP_ERROR_CHECK(usb_host_interface_release(driver_obj.client_hdl, driver_obj.dev_hdl, interface_num ));
// Close the device
ESP_ERROR_CHECK(usb_host_device_close(driver_obj.client_hdl, driver_obj.dev_hdl));
ESP_LOGI(TAG, "Deregistering Client");
ESP_ERROR_CHECK(usb_host_client_deregister(driver_obj.client_hdl));
//Wait to be deleted
ESP_LOGI(TAG, "Giving semaphore");
xSemaphoreGive(signaling_sem);
ESP_LOGI(TAG, "Suspending self");
vTaskSuspend(NULL);
The only special value in here is interface_num
which I declare globally
uint8_t interface_num = 0;
And inside action_get_config_desc()
I added one line
ESP_LOGI(TAG, "SUKU claim interface %d nice", intf_num);
ESP_ERROR_CHECK(usb_host_interface_claim(driver_obj->client_hdl, driver_obj->dev_hdl, intf_num, 0));
// save the intf_num for deregistration
interface_num = intf_num;
usb_host_transfer_alloc(4, 0, &transfer);
This code closes the host driver, after which we can run everything from scratch, and wait for a new device. How to best handle this plug/unplug cycle is up for debate, but I have a task that manages the plugging. It starts the tasks, waits on the semaphore, and then deletes the tasks, in a loop.
static void usb_h_task(void *arg)
{
while(1)
{
ESP_LOGI(TAG, "creating usb host driver tasks");
SemaphoreHandle_t signaling_sem = xSemaphoreCreateBinary();
TaskHandle_t daemon_task_hdl;
TaskHandle_t class_driver_task_hdl;
//Create daemon task
xTaskCreatePinnedToCore(host_lib_daemon_task,
"usb_h_daemon",
4096,
(void *)signaling_sem,
DAEMON_TASK_PRIORITY,
&daemon_task_hdl,
0);
//Create the class driver task
xTaskCreatePinnedToCore(class_driver_task,
"usb_h_class",
4096,
(void *)signaling_sem,
CLASS_TASK_PRIORITY,
&class_driver_task_hdl,
0);
vTaskDelay(10); //Add a short delay to let the tasks run
//Wait for the tasks to complete
xSemaphoreTake(signaling_sem, portMAX_DELAY);
ESP_LOGI(TAG, "deleteting usb host tasks");
//Delete the tasks
vTaskDelete(class_driver_task_hdl);
vTaskDelete(daemon_task_hdl);
}
}
I imagine there are some memory leaks in here, and maybe some unnecessary steps or easier ways to do things, but, I plugged and unplugged like a crazy person and it seems to work well. Ok over and out <3
When I unplug a USB device, the application crashes.
PS. I am fan-boy-ing out over here, all your products are fantastic <3