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.
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.
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)
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 )
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
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.
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
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.
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.
(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)
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.)