-
Notifications
You must be signed in to change notification settings - Fork 7.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[USB] Korg B2 Piano URB Transfer IN never finishes (IDFGH-14421) #15201
Comments
This change was made to support a OYAYO Folding piano, which did not like having its configuration descriptor downloaded multiple times. Again, all these pianos work fine with Windows & MacOS, and they all have a single Configuration Descriptor. There's something specific to the ESP32-S3 causing them to misbehave. Before: // submits control transfer
xesp_usb_config_descriptor_t* pd_usbh_device_getConfigDescriptor(pd_usbh_device_t usbhDevice, uint8_t configIdx, pd_error_t *error)
{
pd_err_unset(error);
xesp_usb_config_descriptor_t* parsed = NULL;
// allocations
pd_usb_transfer_t* transfer = pd_usbh_service_takeTransfer();
{
ESP_LOGI(TAG, "getConfigDescriptor(idx: %" PRIu8 ")", configIdx);
USB_SETUP_PACKET_INIT_GET_CONFIG_DESC((usb_setup_packet_t *)transfer->val->data_buffer,
configIdx,
CONFIG_USB_HOST_CONTROL_TRANSFER_MAX_SIZE);
transfer->val->num_bytes = CONFIG_USB_HOST_CONTROL_TRANSFER_MAX_SIZE + sizeof(usb_setup_packet_t);
transfer->val->flags = 0;
transfer->val->device_handle = usbhDevice.deviceHandleB;
transfer->val->bEndpointAddress = 0;
transfer->val->status = USB_TRANSFER_STATUS_ERROR;
transfer->val->timeout_ms = 500;
transfer->val->context = 0;
eTry(,pd_usbh_service_submitTransferAndWait,(transfer, error));
uint32_t length = transfer->val->actual_num_bytes - sizeof(usb_setup_packet_t);
uint8_t* configDesc = transfer->val->data_buffer + sizeof(usb_setup_packet_t);
// parse
parsed = xesp_usbh_parse_config(configDesc, length, error);
if (!parsed) {
eFail("failed to parse config descriptor");
goto end;
}
pd_err_success(error);
}
end:
pd_usbh_service_giveTransfer(transfer);
eOnFail(return NULL);
return parsed;
} After: // submits control transfer
xesp_usb_config_descriptor_t* pd_usbh_device_getConfigDescriptor(pd_usbh_device_t usbhDevice, uint8_t configIdx, pd_error_t *error)
{
pd_err_unset(error);
// allocations
xesp_usb_config_descriptor_t* parsed = NULL;
{
ESP_LOGI(TAG, "getConfigDescriptor(idx: %" PRIu8 ")", configIdx);
// read
const usb_config_desc_t* desc;
sTry(esp_err_t err =,usb_host_get_active_config_descriptor,(usbhDevice.deviceHandleB, &desc));
// parse
eTry(parsed =,xesp_usbh_parse_config,((uint8_t*) desc, desc->wTotalLength, error));
pd_err_success(error);
}
end:
eOnFail(return NULL);
return parsed;
} |
Thanks for the report.
|
Hi @chipweinberger,
When you schedule the IN transfer, the callback should be called after the data is received by the hardware. Does that mean that literally, you pressed any piano keys and no data appears on the usb? And the same logic works without problem (you can get the callback) on other MIDI-devices, am I right? Is there any specific class-related configuration should be done with some class requests, to setup the device regarding sending back the data? Maybe, Wireshark log from attaching device to Win could help (especially, class specific requests sequence during initialization of the MIDI class driver on the Host side). UPD: Could you also specify what does mean If some devices requires specific index, it might be filtered during the enumeration callback by VID/PID of the device. |
I'll check.
Will do.
Correct.
Sure, I can provide that.
I'm not sure exactly, but the diff I posted fixed it. The descriptors were grabbed (a) automatically by esp-idf & (b) again by my code, and (b) was not working. I expected maybe their firmware was bugged, so I played with it.
Ah I did not realize this. My code also calls SetConfguration. So it's getting called twice. |
So I've found the actual issue! 🎉🎉🎉 In my latest firmware update, I added additional print statement during usb parsing -- ironically to aide in debugging USB issues. I use custom parsing code, since my code was written before esp-idf's. xesp_usb_config_descriptor_t* xesp_usbh_parse_config(uint8_t *data, uint32_t length, pd_error_t* error) {
...
usb_util_print_cfg(config); // causes an issue
...
}
xesp_usb_intf_descriptor_t* xesp_usbh_parse_intf(uint8_t *data, uint32_t length, pd_error_t* error) {
...
usb_util_print_intf(intf); // causes an issue
...
}
xesp_usb_ep_descriptor_t* xesp_usbh_parse_ep(uint8_t *data, uint32_t length, pd_error_t* error) {
...
usb_util_print_ep(ep); // causes an issue
...
} these print functions are just simple utils. They don't recurse or anything like that. All 3 are just like this: void usb_util_print_cfg(const usb_config_desc_t* data){
printf2("Configuration:\n");
if (!data) {printf2("NULL\n\n"); return;}
printf2("bLength: %d\n", data->bLength);
printf2("bDescriptorType: 0x%02x (%s)\n", data->bDescriptorType, usb_descriptor_type_str(data->bDescriptorType));
printf2("wTotalLength: %d\n", data->wTotalLength);
printf2("bNumInterfaces: %d\n", data->bNumInterfaces);
printf2("bConfigurationValue: %d\n", data->bConfigurationValue);
printf2("iConfiguration (string): %d\n", data->iConfiguration);
printf2("bmAttributes: 0x%02x\n", data->bmAttributes);
printf2("bMaxPower: %d mA\n\n", data->bMaxPower * 2);
} For whatever reason, perhaps timing related, these USB devices do not like this. It's a bit surprising, but also extremely reproducible. I will close this issue. @peter-marcisovsky @roma-jam, I'm you'd like to understand the underlying mechanism of failure more. Unfortunately, I don't have time or a need to dig deeper right now. But the offending device is a Korg B2. This one. |
So I spoke too soon, this issue is back when using a 'production' device with Bluetooth and Wifi enabled. I'm not sure if BLE & Wifi is related, but it seems like anything like that could affect timing. Especially, I have a BLE message static void clientEventsCallback(const usb_host_client_event_msg_t *event, void *arg)
{
if (event->event == USB_HOST_CLIENT_EVENT_NEW_DEV)
{
// COMMENTED OUT - the extra time needed to send this bluetooth alert
// causes the KORG B2 piano to not initialize properly
//pd_alerts_push(PD_ALERT_USB_STATE);
//A new device has been enumerated and added to the USB Host Library
ESP_LOGI(TAG, "[client task] NEW_DEV! addr: %" PRIu8 "", event->new_dev.address);
bool success = xQueueSend(xDeviceConnectedEvents, &event->new_dev.address, portMAX_DELAY);
if (!success)
{
pd_raise_uie_e2("usbhQueue",TAG, "[client task] xQueueSend NEW DEV failed");
}
}
else if (event->event == USB_HOST_CLIENT_EVENT_DEV_GONE)
{
// A device opened by the client is now gone
usb_device_handle_t deviceHandle = event->dev_gone.dev_hdl;
ESP_LOGW(TAG, "[client task] DEV_GONE dev_hdl: %p", deviceHandle);
pd_error_t errorBase;
pd_error_t* error = &errorBase;
pd_err_init_lite(error);
closeDeviceBase(pd_usbh_device_create(deviceHandle), true /*isDeviceGone*/, error);
if (is_fail(error)){
pd_raise_uie_e2("usbhClose",TAG, "[client task] usb_host_device_close() failed");
}
}
else
{
// raise issue
pd_raise_uie_e2("usbhUnknown", TAG, "[client task] unknown event %" PRIu32 "", event->event);
}
} |
In summary, Im not sure if there is anything in esp-idf that needs to change / should change to avoid issues like this. |
USB_HOST_CLIENT_EVENT_NEW_DEV and USB_HOST_CLIENT_EVENT_DEV_GONE are called within Calling any other things such as If there will be anything, that requires time, the USB will be waiting for these logic to end to proceed handle the USB events. So, if you don't want any other tasks affect USB, you should keep them out of the task, which handles USB. |
Yes, it makes sense. However, the Notably, I also have
|
Answers checklist.
IDF version.
v5.1.4
Espressif SoC revision.
ESP32-S3
Operating System used.
macOS
How did you build your project?
Command line with idf.py
If you are using Windows, please specify command line type.
None
Development Kit.
custom pcb
Power Supply used.
USB
What is the expected behavior?
I am the creator of Jamcorder.
I have over 300 devices out in the wild, and the large majority connect to and communicate with their piano just fine. They can send MIDI OUT (data sent to usb piano) no problem. However for a few pianos, MIDI IN (receiving data from usb piano) does not work.
These devices work fine when plugged into a Windows or MacOS computer. So the problem is something related to the ESP32-S3.
Im calling
usb_host_transfer_submit
, but it just never calls the callback.What is the actual behavior?
Im calling
usb_host_transfer_submit
on the MIDI IN, but it just never calls the callback.Steps to reproduce.
usb_host_transfer_submit
on USB IN endpointDebug Logs.
More Information.
No response
The text was updated successfully, but these errors were encountered: