Libavr32 device detection help

Summary - is there a libavr32/USB wizard here who could help me figure out hacking ansible/trilogy device detection to use DIY usb devices?

Full Story:
I am working on a couple of DIY devices which speak monome serial (grid and arc clones for lack of a better term). These are based on a Teensy 3.x micro controller.

I’ve gotten these working pretty well communicating with serialosc (Max on MacOS) and libmonome (Norns on linux/raspberryPi) with minimal hacking.

So then I wonder can I also get these working with ansible or trilogy modules? Answer: nope - or at least not without some serious hacking

Which leads me to libavr32 source code and trying to figure out how its device detection works. It looks like the magic happens in uhi_ftdi.c but a bunch of that magic looks very specific to the monome hardware and USB wizardry (usb interface-class, interface-protocol, attributes, configuring endpoints, etc.) which is a little over my head.

I’d like to find out how other devices (i.e. Teensy) could be recognized as “valid” and try to make my DIY devices show up for ansible/trilogy modules.

Any help would be greatly appreciated. Thx!

I wrote most of that horrible code back in 2012 or so. Will try and find a minute to dig into it. Anything you can say about how the teensy is configured, would be useful.

Here’s the deal: libmonone just thinks the device is a normal serial port and relies the FTDI driver to achieve that illusion. In libavr32 there is no such driver, hence the need to basically emulate it.

1 Like

Awesome!

Teensy code is pretty much just doing serial read and writes (sending chunks of serial monome data).

Below is a lsusb -v dump from my teensy-grid which has the USB descriptors and whatnot.

I’ve hacked the iManufacturer/iProduct/iSerial info for the teensy so it impersonates a grid (for libmonome).

in uhi_ftdi.c I get lost around line 105 where it looks at conf_desc_lgt
no idea where the values for USB_DT_INTERFACE and USB_DT_ENDPOINT are coming from

I hacked around the FTDI_VID and FTDI_VID check, but FTDI_CLASS and FTDI_PROTOCOL don’t match monome (both are set to 0xFF/255 in usb_protocol_ftdi.h) so it kinda dies around there.

Bus 001 Device 041: ID 16c0:0483 Van Ooijen Technische Informatica Teensyduino Serial
Device Descriptor:
  bLength                18
  bDescriptorType         1
  bcdUSB               1.01
  bDeviceClass            2 Communications
  bDeviceSubClass         0 
  bDeviceProtocol         0 
  bMaxPacketSize0        64
  idVendor           0x16c0 Van Ooijen Technische Informatica
  idProduct          0x0483 Teensyduino Serial
  bcdDevice            2.00
  iManufacturer           1 monome
  iProduct                2 monomegrid
  iSerial                 3 m4676000
  bNumConfigurations      1
  Configuration Descriptor:
    bLength                 9
    bDescriptorType         2
    wTotalLength           67
    bNumInterfaces          2
    bConfigurationValue     1
    iConfiguration          0 
    bmAttributes         0xc0
      Self Powered
    MaxPower              100mA
    Interface Descriptor:
      bLength                 9
      bDescriptorType         4
      bInterfaceNumber        0
      bAlternateSetting       0
      bNumEndpoints           1
      bInterfaceClass         2 Communications
      bInterfaceSubClass      2 Abstract (modem)
      bInterfaceProtocol      1 AT-commands (v.25ter)
      iInterface              0 
      CDC Header:
        bcdCDC               1.10
      CDC Call Management:
        bmCapabilities       0x01
          call management
        bDataInterface          1
      CDC ACM:
        bmCapabilities       0x06
          sends break
          line coding and serial state
      CDC Union:
        bMasterInterface        0
        bSlaveInterface         1 
      Endpoint Descriptor:
        bLength                 7
        bDescriptorType         5
        bEndpointAddress     0x82  EP 2 IN
        bmAttributes            3
          Transfer Type            Interrupt
          Synch Type               None
          Usage Type               Data
        wMaxPacketSize     0x0010  1x 16 bytes
        bInterval              64
    Interface Descriptor:
      bLength                 9
      bDescriptorType         4
      bInterfaceNumber        1
      bAlternateSetting       0
      bNumEndpoints           2
      bInterfaceClass        10 CDC Data
      bInterfaceSubClass      0 Unused
      bInterfaceProtocol      0 
      iInterface              0 
      Endpoint Descriptor:
        bLength                 7
        bDescriptorType         5
        bEndpointAddress     0x03  EP 3 OUT
        bmAttributes            2
          Transfer Type            Bulk
          Synch Type               None
          Usage Type               Data
        wMaxPacketSize     0x0040  1x 64 bytes
        bInterval               0
      Endpoint Descriptor:
        bLength                 7
        bDescriptorType         5
        bEndpointAddress     0x84  EP 4 IN
        bmAttributes            2
          Transfer Type            Bulk
          Synch Type               None
          Usage Type               Data
        wMaxPacketSize     0x0040  1x 64 bytes
        bInterval               0
Device Status:     0x0000
  (Bus Powered)

Not sure what other info you need on the teensy

ok, so the teensy is configured as a CDC class device, which is pretty different from FTDI devices. (the latter are not class-compliant at all, hence need for driver to support arbitrary endpoints for setting baudrate, &c; and hence the all-on mask for the class/protocol fields.)

so, the broad story is that we are using the HAL stack called the Atmel Software Framework (now the Advanced Software Framework, since Atmel -> Microchip)

the ASF includes the USB host stack and device drivers for standard USB device classes, including CDC. through some convoluted makefiles, the ASF host driver pulls in our conf_usb_host.h, which is where we say which UHIs we support (UHI == USB Host Interface :face_vomiting:)

somewhere in the non-stripped-down version of the ASF you should be able to find a demo of using a CDC device with an AVR32 host. you will want to add a new UHI for these devices alongside FTDI, HID, MSC and MIDI.

libavr32 UHI sources for class-compliant devices (not FTDI) are pretty simple, they just lightly customize the generic templates from the ASF to do different things with the data.

the CDC UHI template stuff is in asf/common/services/usb/class/cdc/host.

oh, those are in asf/common/services/usb/usb_protocol.h, and are standard fields in the USB2 data structures.

hope this helps a little, sorry my memory is a little fuzzy.
and very sorry for those disgusting sourcefiles, omg

something like this?:

EDIT: Whoa - this may be a bit over my head :confused:

flying by the seat of my pants, but here’s a start based on example code

EDIT for url

ah, no - that’s an example of setting up the avr32 as a USB-CDC device. which is, i’m afraid, substantially simpler.

here’s the relevant example:

what this example does is simply makes a bridge between the host’s hardware UART and a connected CDC device.

probably the most important part is the conf_usb_host.h header:
[ https://github.com/marekr/asf/blob/master/common/services/usb/class/cdc/host/example/conf_usb_host.h ]

this is a customization of the “template” header (all the ASF drivers and examples are structured this way)
[ https://github.com/marekr/asf/blob/master/common/services/usb/class/cdc/host/module_config/conf_usb_host.h ]

we have an analogous conf_usb_host.h in libavr32. its purpose is to glue our own functions to the driver using #defines.

we ended up customizing the sources like uhi_hid.h/.c, TBH i can’t exactly remember why - i think we didn’t want to use the same assumptions about how incoming data was parsed.

but you may not need to customize the driver really; the example just uses the conf header to define an rx function (i think): [ https://github.com/marekr/asf/blob/master/common/services/usb/class/cdc/host/example/conf_usb_host.h#L122 ]

those handlers are defined in the example by ui,h and ui.c (the latter is board-specific). you would want to make usb/cdc.c or something, which would do the actual work of parsing bytes and calling grid functions.

once you have a working conf header and handler functions, you would add UHI_CDC to the list of supported UHIs in the conf, and it should just sort of automagically work when uhc_start() is called from the main init module.


yes… this level of libavr32 hacking is not for the faint of heart, i’d budget some time accordingly

oh nice! that was quick.

sorry for the wall of text - i guess the only still-relevant point is that you may not really need the custom driver at all? i really can’t remember why we needed it exactly - maybe the ASF method wasn’t set up to have different handlers for different device classes.

Yeah - looks like to found some of the same stuff you posted and was just getting the github stuff wrangled when you posted it.

gonna try throwing some debug statements in and see if it’ll compile or do anything.

:slight_smile:

Do I need to include or reference usb/cdc.c anywhere?

oh - yes, you need to add new sources to the config.mk of the module you’re building. somewhat confusingly i suppose, this includes all libavr32 sources.

like here for ansible:
[ https://github.com/monome/ansible/blob/master/src/config.mk ]

(iirc, at some point we had this inclusion step more encapsulated in the lib, but it proved desirable to let different modules override different parts of the lib and this was the easiest way)

great! and then…

this errors:

#define UHI_CDC_CHANGE(dev, b_plug) cdc_change(dev, b_plug)
extern bool cdc_change(uhc_device_t* dev, bool b_plug);

do i want to move that extern bool to my cdc.c file?

put those declarations in cdc.h and include cdc.h in uhi_cdc.c

1 Like

welp… i got something that kinda compiles for ansible at last
libavr32 change
ansible changes

(some errors about error: implicit declaration of function 'callback_cdc_change' that I gotta look up later)

doesn’t do anything yet, but feels like the framework is there now. :+1:

I remember you were talking about shipping a DIY grid from one to another to eventually work on this some weeks ago.

I should soon have an Ansible to test with, already have a DIY 128 grid, and should soon have some free evenings as well. I wonder if I should (also) start looking at implementing the support for CDC devices in current libavr32, or if this is already being worked on…?

(Can offer help with testing too, of course, if it looks like it would be duplicate work otherwise.)

that’s ok, i’ll work on it.

1 Like

Great! In case you need any help due to lack of time / other more important projects / similar, do feel free to ping me.

1 Like