How should USB MIDI packets be formatted?

43 Views Asked by At

I have an LPC1768 microcontroller based device that I want to talk over USB3.0 to my laptop. The microcontroller end is USB-C (and has the proper pulldowns), and laptop end is USB-A. The packets I'm sending are Midi Show Control (MSC). I'm reading these packets from USBPcap through Wireshark.

The packets are somehow malformed, and the only resource I've been able to find is the USB Device Class Definition for MIDI Devices. There are no other devices on the bus. Here is an example of one packet - the MSC data being sent is from the highlighted f0 octet to the end. This matches the MSC spec linked above. The info in the dropdowns on bottom left lead me to believe this is being parsed as two MIDI Event packets for some reason.

enter image description here

As seen in the above image, my laptop (host) responds with a URB_BULK in each time. I can't find any mention of this in the device class spec or any other documentation regarding MIDI over USB or MSC. I'm not sure what part of the protocol this is. Here is the URB_BULK.

enter image description here

The device mounts/enumerates as a "USB Composite Device". The MSC messages are not detected by MSC-receiving software or MSC-specific packet sniffers.

I've tried modifying the MSC packet that I'm sending, manipulating the timing, changing packet length mask, RD_EN/WR_EN bits, endpoints, and changing the mounting/enumeration process and bus init. What is wrong with the data I'm sending? How can I get it to conform to the expected format?

This is some of the relevant code. ep_write is from usbcore.cpp in the mbed OS. I can figure out how to change my code if I know what the sent packet should look like, I just need to know how what I'm sending differs from that format.

#define TxENDPKT (1<<7)
#define WR_EN (1<<1)
#define LOG_ENDPOINT(ep) ((ep>>1)<<2)
void ep_write(uint8_t ep, uint8_t *tbuf, uint32_t len) {
    uint32_t *buf = (uint32_t*) tbuf;
    LPC_USB->USBCtrl   = LOG_ENDPOINT(ep)|WR_EN; // RD_EN bit and LOG_ENDPOINT  
    LPC_USB->USBTxPLen |= (len & 0x3FF);         // write and mask packet length
    while (!(LPC_USB->USBDevIntSt & TxENDPKT)) {
        LPC_USB->USBTxData = *buf++;
    }
    LPC_USB->USBCtrl = 0;
    LPC_USB->USBDevIntClr |= TxENDPKT;
    sie_command(SIE_SEL_EP+ep);     // select endpoint   
    sie_command(SIE_VAL_BUFFER);    // validate TX buffer
}

/*
Takes command byte (0x06 for set), data pointer, and data length.
Sends a formatted MSC message over serial.
Returns 0 on success.
*/
int sendMSC(uint8_t command, uint8_t *data, int datalen) {
    uint8_t msc_packet[] = {0xF0, 0x7F, 0x7F, 0x02, 0x7F, command};
    /*[F07F] header, marks univ sys ex/realtime
      [7F] target device (broadcast)
      [02] MSC specifier
      [7F] command format (all)*/
    memcpy(msc_packet + 6, data, datalen); //copy data to end of msc packet
    uint8_t msc_close = 0xF7; //closing octet
    memcpy(msc_packet + 6 + datalen, &msc_close, 1);
    
    if (VERBOSE) {
        debug(("Sending MSC packet => "));
        for (int i = 0; i < 7 + datalen; ++i) {
            debug(("%x ", msc_packet[i]));
        }
        debug(("\n"));
    }
    ep_write(EP5, msc_packet, 7 + datalen);
    return 0;
}

USBTreeView results: enter image description here

After changing it to an HID-compliant device using mbed's USBHID library: enter image description here

0

There are 0 best solutions below