adafruit / Adafruit_TinyUSB_Arduino

Arduino library for TinyUSB
MIT License
469 stars 122 forks source link

USB MIDI device name not being changed #201

Closed jhsa closed 7 months ago

jhsa commented 2 years ago

Operating System

Windows 10

IDE version

Arduino 1.8.19

Board

Wemos ESP32-S2 Mini

ArduinoCore version

Espressif Systems Version 2.0.3

TinyUSB Library version

Version 1.14.3

Sketch (attached txt file)

#include <Arduino.h>
#include <Adafruit_TinyUSB.h>
#include <MIDI.h>

// USB MIDI object
Adafruit_USBD_MIDI usb_midi;

// Create a new instance of the Arduino MIDI Library,
// and attach usb_midi as the transport.
MIDI_CREATE_INSTANCE(Adafruit_USBD_MIDI, usb_midi, MIDI);

// Variable that holds the current position in the sequence.
uint32_t position = 0;

// Store example melody as an array of note values
byte note_sequence[] = {
  74,78,81,86,90,93,98,102,57,61,66,69,73,78,81,85,88,92,97,100,97,92,88,85,81,78,
  74,69,66,62,57,62,66,69,74,78,81,86,90,93,97,102,97,93,90,85,81,78,73,68,64,61,
  56,61,64,68,74,78,81,86,90,93,98,102
};

void setup()
{
#if defined(ARDUINO_ARCH_MBED) && defined(ARDUINO_ARCH_RP2040)
  // Manual begin() is required on core without built-in support for TinyUSB such as mbed rp2040
  TinyUSB_Device_Init(0);
#endif

  pinMode(LED_BUILTIN, OUTPUT);

//  usb_midi.setStringDescriptor("TinyUSB MIDI");
  TinyUSBDevice.setProductDescriptor("TinyUSB MIDI");

  // Initialize MIDI, and listen to all MIDI channels
  // This will also call usb_midi's begin()
  MIDI.begin(MIDI_CHANNEL_OMNI);

  // Attach the handleNoteOn function to the MIDI Library. It will
  // be called whenever the Bluefruit receives MIDI Note On messages.
  MIDI.setHandleNoteOn(handleNoteOn);

  // Do the same for MIDI Note Off messages.
  MIDI.setHandleNoteOff(handleNoteOff);

  Serial.begin(115200);

  // wait until device mounted
  while( !TinyUSBDevice.mounted() ) delay(1);
}

What happened ?

The line:

TinyUSBDevice.setProductDescriptor("TinyUSB MIDI");

should apparently change the USB device's product name, but it doesn't. The Midi device is still detected as "LOLIN-S2-MINI"

Also the line: usb_midi.setStringDescriptor("TinyUSB MIDI"); doesn't seem to do anything.

How to reproduce ?

Flash the code to the ESP32-S2 Mini board, connect it to the computer's USB port, open the MIDI Monitor software, and check the MIDI device In/Out ports name. It should have changed to what I set in the code, but it doesn't.

There seems to be very little information about how to use this library on the internet, specially with midi. Perhaps I am doing something wrong as I am a beginner, but this looks like a bug to me. As I said, there is very little information on this subject. Or at least I cannot find it.

Debug Log

No response

Screenshots

No response

kaysievers commented 1 year ago

If you change the product id (the 16 bit number) of the board, does this device show up with the new name?

Windows and macOS retrieve the names only the first time and store them, so it might not get picked up on the same machine.

On Windows it might already work to use a different USB port, it usually stores the config per port.

There is a free tool for Windows to remove existing USB registry entries, which the system has stored for the devices when they are connected back: https://www.nirsoft.net/utils/usb_devices_view.html

Better be careful not to change other things, or don't remove things that might be needed for other USB devices.

oiresgleichen commented 1 year ago

Same at Esp32 S3. :-(

Robinyoh commented 1 year ago

Same for me on OSX both lines doesn't change the midi port name. It takes the board name you have chosen in board manager, if I change that the midi port name changes to for example Deneyap mini:

I'm on Arduino IDE 2.0.4, Tiny_USB 1.18.3

todbot commented 1 year ago

If it helps, this issue has nothing to do with MIDI, but with the USB device descriptor not being changed by the TinyUSBDevice.setManufacturerDescriptor() and similar methods on ESP32-S2 (S3?)

The code below on ESP32-S2 using Adafruit_TinyUSB_Library@2.2.0 and arduino-esp32@2.0.9, does NOT change the USB Device Descriptor, as one would expect.

#include <Adafruit_TinyUSB.h>
void setup() {
  TinyUSBDevice.setManufacturerDescriptor("todbot");
  TinyUSBDevice.setProductDescriptor("Tester");
  Serial.begin(115200);
}
void loop() {
  Serial.println("hello");
  delay(500);
}
LouDou commented 11 months ago

these values are being pulled in from .platformio/packages/framework-arduinoespressif32/variants/lolin_s2_mini/pins_arduino.h

#define USB_MANUFACTURER    "WEMOS.CC"
#define USB_PRODUCT         "LOLIN-S2-MINI"

There seems to be some disconnect between this library layer and whatever the espressif32 framework is doing to set up the device descriptors. It would be nice to correctly manipulate the descriptors from this side.

There's a comment and ifdef in this libary which stubs out the descriptor handling in Adafruit TinyUSB Library/src/arduino/Adafruit_USBD_Device.cpp

// EPS32 use built-in core descriptor builder.
// Therefore most of descriptors are stubs only
#ifdef ARDUINO_ARCH_ESP32

therefore it seems that this library does not attempt at all to set up any descriptors on ESP32, and uses the framework defaults.

If I change this ifdef so that the else clause is compiled, then setting the strings from my application code works as expected

#ifdef DISABLED_ARDUINO_ARCH_ESP32

I only had to comment out one other line (329)

  // SerialTinyUSB.begin(115200);

Minimal example which works with the above modifications

#include <Arduino.h>
#include <Adafruit_TinyUSB.h>

Adafruit_USBD_MIDI usb_midi(1);

void setup()
{
  Serial.begin(115200);

  TinyUSBDevice.clearConfiguration();
  TinyUSBDevice.setManufacturerDescriptor("Your Name");
  TinyUSBDevice.setProductDescriptor("Your Thing");
  TinyUSBDevice.setSerialDescriptor("Your Thing CDC");

  usb_midi.setCableName(1, "Your Thing Port");

  usb_midi.begin();
}

void loop()
{
  delay(1000);
  Serial.printf(".");
}

Caveat though that in this setup there is no usb serial console ... so no debug interface and you have to manually put the device into flash boot mode to update the firmware.

LouDou commented 11 months ago

And to make the USB Serial work again, you can construct your own basic class for this

class MyUSBCDC : public Adafruit_USBD_CDC, public Adafruit_USBD_Interface
{
public:
  MyUSBCDC(uint8_t itf = 0) : Adafruit_USBD_CDC(itf)
  {
  }

  virtual uint16_t getInterfaceDescriptor(uint8_t itfnum, uint8_t *buf,
                                          uint16_t bufsize)
  {
    // EPOUT = 0x00;
    // EPIN = 0x80;

    // CDC is mostly always existed for DFU
    // usb core will automatically update endpoint number
    uint8_t desc[] = {TUD_CDC_DESCRIPTOR(itfnum, 0, 0x80, 8, 0x00, 0x80, 64)};
    uint16_t const len = sizeof(desc);

    if (bufsize < len)
    {
      return 0;
    }

    memcpy(buf, desc, len);
    return len;
  }
};

MyUSBCDC USBSerial(0);

void setup() {

  USBSerial.begin(115200);

  TinyUSBDevice.clearConfiguration();
  TinyUSBDevice.setManufacturerDescriptor("Your Name");
  TinyUSBDevice.setProductDescriptor("Your Thing");
  TinyUSBDevice.setSerialDescriptor("Your Thing CDC");
  TinyUSBDevice.addInterface(USBSerial);
}

Then use USBSerial in your app code instead of Serial. This also allows the upload to work again without manually entering DFU.

Robinyoh commented 7 months ago

Thanks @LouDou for your nice explained workaround. It works very good! Now I can finally name my MIDI remote project interface :-)

One thing to know for other people is that the midi name is a sum of TinyUSBDevice.setProductDescriptor and usb_midi.setCableName I have experienced on a ESP32 S2 Mini

jhsa commented 7 months ago

Thank you. Will this fix also work with USB Midi?

Robinyoh commented 7 months ago

not sure, I'm now noticing that with this workaround I can only change the name ones. After changing it to an other name it keeps the name from before. Looks like it is stored somewhere in Arduino software? Uploading to an other esp32 s2 mini also giving the MIDI port name from before.

First selected the board as a Lolin S2 mini giving a name and keeps this name. Then selected it as a Denayap mini and can ones change the name.

hathach commented 7 months ago

function is currently not support for ESP32

jhsa commented 7 months ago

function is currently not support for ESP32

So, what is not supported? Changing the name of the device or USB Midi all together? USB Midi was supported before as I use it on some of my DIY projects.

hathach commented 7 months ago

dynamic change of descriptors, it is in the readme

jhsa commented 7 months ago

dynamic change of descriptors, it is in the readme

You mean this?

ESP32 port relies on Espressif's esp32-hal-tinyusb.c for building usb descriptors which requires all descriptors must be specified in usb objects declaration i.e constructors. Therefore all descriptor-related fields must be part of object declaration and descriptor-related API have no effect afterwards for this port.

hathach commented 7 months ago

There is an on going PR that rework how descriptors is built/integrated with arduino-esp32 core, which allow dynamic descriptors for esp32. You can try it out https://github.com/adafruit/Adafruit_TinyUSB_Arduino/pull/372, let me know if that works for you. If everything go well we can release it as v3

Robinyoh commented 6 months ago

@LouDou Do you know where Arduino software stores the Descriptor names that your workaround alters? because it looks like it is changing it for the selected board and remembers it some where and I can't change it. first time I did it with Lolin S2 mini and after that with Deneyap mini selected.. So I have now 2 versions I can chose out, but like to change it. Or do I need to reinstall Arduino IDE?

@hathach I don't understand what I need to do to test your PR

LouDou commented 6 months ago

@Robinyoh I wouldn't know, sorry. I actually moved to using esp-idf for my usb projects.

hathach commented 6 months ago

@Robinyoh it is merged, just bump up library to latest 3.x to test with.