khimaros / ambit

Take control of your Palette.
GNU General Public License v3.0
18 stars 2 forks source link

add support for MonogramCC devices #2

Open thattommyhall opened 2 years ago

thattommyhall commented 2 years ago
Bus 001 Device 013: ID 0483:a2c5 STMicroelectronics Monogram Core Module

I tried setting it in ambit/controller

 class Device:
     def __init__(self, device_id, interface_id, index=0):
         vendor_id, product_id = device_id.split(':')
-        self.vendor_id = int(vendor_id, 16)
-        self.product_id = int(product_id, 16)
+        # self.vendor_id = int(vendor_id, 16)
+        # self.product_id = int(product_id, 16)
+        self.vendor_id = int("0483", 16)
+        self.product_id = int("a2c5", 16)

but then I get an error from pyusb

❯ ambit_console
[0] Choosing device at USB discovery index 0.
[0] Waiting for initial layout ...
Exception in thread Thread-2:
Traceback (most recent call last):
  File "/home/thattommyhall/Dropbox/Projects/ambit/.direnv/python-3.9.7/lib/python3.9/site-packages/usb/core.py", line 223, in get_interface_and_endpoint
    return self._ep_info[endpoint_address]
KeyError: 5

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/usr/lib/python3.9/threading.py", line 973, in _bootstrap_inner
    self.run()
  File "/usr/lib/python3.9/threading.py", line 910, in run
    self._target(*self._args, **self._kwargs)
  File "/home/thattommyhall/Dropbox/Projects/ambit/ambit/controller.py", line 264, in bulk_write_worker
    self.bulk_write(data)
  File "/home/thattommyhall/Dropbox/Projects/ambit/ambit/controller.py", line 277, in bulk_write
    self.handle.bulkWrite(
  File "/home/thattommyhall/Dropbox/Projects/ambit/.direnv/python-3.9.7/lib/python3.9/site-packages/usb/legacy.py", line 154, in bulkWrite
    return self.dev.write(endpoint, buffer, timeout)
  File "/home/thattommyhall/Dropbox/Projects/ambit/.direnv/python-3.9.7/lib/python3.9/site-packages/usb/core.py", line 940, in write
    intf, ep = self._ctx.setup_request(self, endpoint)
  File "/home/thattommyhall/Dropbox/Projects/ambit/.direnv/python-3.9.7/lib/python3.9/site-packages/usb/core.py", line 102, in wrapper
    return f(self, *args, **kwargs)
  File "/home/thattommyhall/Dropbox/Projects/ambit/.direnv/python-3.9.7/lib/python3.9/site-packages/usb/core.py", line 215, in setup_request
    intf, ep = self.get_interface_and_endpoint(device, endpoint_address)
  File "/home/thattommyhall/Dropbox/Projects/ambit/.direnv/python-3.9.7/lib/python3.9/site-packages/usb/core.py", line 102, in wrapper
    return f(self, *args, **kwargs)
  File "/home/thattommyhall/Dropbox/Projects/ambit/.direnv/python-3.9.7/lib/python3.9/site-packages/usb/core.py", line 231, in get_interface_and_endpoint
    raise ValueError('Invalid endpoint address ' + hex(endpoint_address))
ValueError: Invalid endpoint address 0x5
khimaros commented 2 years ago

hi @thattommyhall thank you for the report. i'm excited to see some new hardware being tested!

you should be able to set alternative device ids with the flag --device=0483:a2c5 rather than modifying the code. this should make testing a bit easier and should work with any ambit command.

a few ideas to help troubleshoot:

can you include the output of lsusb -vvv -d 0483:a2c5? this should help us find the right endpoint.

thattommyhall commented 2 years ago

Thanks for the swift response!

Bus 001 Device 006: ID 0483:a2c5 STMicroelectronics Monogram Core Module
Device Descriptor:
  bLength                18
  bDescriptorType         1
  bcdUSB               2.00
  bDeviceClass          239 Miscellaneous Device
  bDeviceSubClass         2 
  bDeviceProtocol         1 Interface Association
  bMaxPacketSize0        64
  idVendor           0x0483 STMicroelectronics
  idProduct          0xa2c5 
  bcdDevice            2.00
  iManufacturer           1 Monogram
  iProduct                2 Monogram Core Module
  iSerial                 3 3F2D4C4160
  bNumConfigurations      1
  Configuration Descriptor:
    bLength                 9
    bDescriptorType         2
    wTotalLength       0x00c0
    bNumInterfaces          5
    bConfigurationValue     1
    iConfiguration          4 Monogram Standard Configuration
    bmAttributes         0x80
      (Bus Powered)
    MaxPower              500mA
    Interface Association:
      bLength                 8
      bDescriptorType        11
      bFirstInterface         0
      bInterfaceCount         2
      bFunctionClass          2 Communications
      bFunctionSubClass       2 Abstract (modem)
      bFunctionProtocol       1 AT-commands (v.25ter)
      iFunction               6 Monogram Serial IAD Collection
    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              7 Monogram Serial Abstract Control Model
      CDC Header:
        bcdCDC               1.10
      CDC Call Management:
        bmCapabilities       0x00
        bDataInterface          1
      CDC ACM:
        bmCapabilities       0x02
          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     0x0008  1x 8 bytes
        bInterval              16
    Interface Descriptor:
      bLength                 9
      bDescriptorType         4
      bInterfaceNumber        1
      bAlternateSetting       0
      bNumEndpoints           2
      bInterfaceClass        10 CDC Data
      bInterfaceSubClass      0 
      bInterfaceProtocol      0 
      iInterface              8 Monogram Serial Data
      Endpoint Descriptor:
        bLength                 7
        bDescriptorType         5
        bEndpointAddress     0x01  EP 1 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     0x81  EP 1 IN
        bmAttributes            2
          Transfer Type            Bulk
          Synch Type               None
          Usage Type               Data
        wMaxPacketSize     0x0040  1x 64 bytes
        bInterval               0
    Interface Descriptor:
      bLength                 9
      bDescriptorType         4
      bInterfaceNumber        2
      bAlternateSetting       0
      bNumEndpoints           1
      bInterfaceClass         3 Human Interface Device
      bInterfaceSubClass      0 
      bInterfaceProtocol      0 
      iInterface              9 Monogram HID
        HID Device Descriptor:
          bLength                 9
          bDescriptorType        33
          bcdHID               1.11
          bCountryCode            0 Not supported
          bNumDescriptors         1
          bDescriptorType        34 Report
          wDescriptorLength     357
         Report Descriptors: 
           ** UNAVAILABLE **
      Endpoint Descriptor:
        bLength                 7
        bDescriptorType         5
        bEndpointAddress     0x83  EP 3 IN
        bmAttributes            3
          Transfer Type            Interrupt
          Synch Type               None
          Usage Type               Data
        wMaxPacketSize     0x0010  1x 16 bytes
        bInterval               1
    Interface Descriptor:
      bLength                 9
      bDescriptorType         4
      bInterfaceNumber        3
      bAlternateSetting       0
      bNumEndpoints           0
      bInterfaceClass         1 Audio
      bInterfaceSubClass      1 Control Device
      bInterfaceProtocol      0 
      iInterface             10 Monogram MIDI
      AudioControl Interface Descriptor:
        bLength                 9
        bDescriptorType        36
        bDescriptorSubtype      1 (HEADER)
        bcdADC               1.00
        wTotalLength       0x0009
        bInCollection           1
        baInterfaceNr(0)        4
    Interface Descriptor:
      bLength                 9
      bDescriptorType         4
      bInterfaceNumber        4
      bAlternateSetting       0
      bNumEndpoints           2
      bInterfaceClass         1 Audio
      bInterfaceSubClass      3 MIDI Streaming
      bInterfaceProtocol      0 
      iInterface             11 MG MIDI Stream
      MIDIStreaming Interface Descriptor:
        bLength                 7
        bDescriptorType        36
        bDescriptorSubtype      1 (HEADER)
        bcdADC               1.00
        wTotalLength       0x0041
      MIDIStreaming Interface Descriptor:
        bLength                 6
        bDescriptorType        36
        bDescriptorSubtype      2 (MIDI_IN_JACK)
        bJackType               1 Embedded
        bJackID                 1
        iJack                   0 
      MIDIStreaming Interface Descriptor:
        bLength                 6
        bDescriptorType        36
        bDescriptorSubtype      2 (MIDI_IN_JACK)
        bJackType               2 External
        bJackID                 2
        iJack                   0 
      MIDIStreaming Interface Descriptor:
        bLength                 9
        bDescriptorType        36
        bDescriptorSubtype      3 (MIDI_OUT_JACK)
        bJackType               1 Embedded
        bJackID                 3
        bNrInputPins            1
        baSourceID( 0)          2
        BaSourcePin( 0)         1
        iJack                   0 
      MIDIStreaming Interface Descriptor:
        bLength                 9
        bDescriptorType        36
        bDescriptorSubtype      3 (MIDI_OUT_JACK)
        bJackType               2 External
        bJackID                 4
        bNrInputPins            1
        baSourceID( 0)          1
        BaSourcePin( 0)         1
        iJack                   0 
      Endpoint Descriptor:
        bLength                 9
        bDescriptorType         5
        bEndpointAddress     0x04  EP 4 OUT
        bmAttributes            2
          Transfer Type            Bulk
          Synch Type               None
          Usage Type               Data
        wMaxPacketSize     0x0040  1x 64 bytes
        bInterval               0
        bRefresh                0
        bSynchAddress           0
        MIDIStreaming Endpoint Descriptor:
          bLength                 5
          bDescriptorType        37
          bDescriptorSubtype      1 (GENERAL)
          bNumEmbMIDIJack         1
          baAssocJackID( 0)       1
      Endpoint Descriptor:
        bLength                 9
        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
        bRefresh                0
        bSynchAddress           0
        MIDIStreaming Endpoint Descriptor:
          bLength                 5
          bDescriptorType        37
          bDescriptorSubtype      1 (GENERAL)
          bNumEmbMIDIJack         1
          baAssocJackID( 0)       3
can't get device qualifier: Resource temporarily unavailable
can't get debug descriptor: Resource temporarily unavailable
Device Status:     0x0000
  (Bus Powered)
khimaros commented 2 years ago

try modifying ambit/controller.py:79

-    USB_ENDPOINT_BULK_OUT = 0x05
+    USB_ENDPOINT_BULK_OUT = 0x04
thattommyhall commented 2 years ago

seems to hang at

[0] Waiting for initial layout ...
khimaros commented 2 years ago

could you try running with --verbose and see if there is any other information available?

thattommyhall commented 2 years ago

nothing extra is printed im afraid

khimaros commented 2 years ago

oops, that should be --debug. if that doesn't give anything, maybe we can hop on a chat and i can provide you with a patch to increase the verbosity even further. this is my first interaction with a MonogramCC device, so thank you for the patience.

thattommyhall commented 2 years ago
❯ ambit_console --device=0483:a2c5 --debug
[0] Choosing device at USB discovery index 0.
[0] Waiting for initial layout ...
[@] BULK WRITE: {"start":1}
[@] BULK WRITE: {"hidmap":[]}{"joymap":[]}{"midimap":[]}{"led":[]}
[@] BULK WRITE: {"send_version":1}

I'd be happy to share a tmux session (but not tonight!) or pay for a new core module for you (ideally in the next 24h as they have a promo), email thattommyhall@gmail.com to discuss

khimaros commented 2 years ago

you should have something in your inbox (or spam folder)!

khimaros commented 2 years ago

i'm still waiting on the new devices to be delivered. i'll post an update here once i receive them.

khimaros commented 2 years ago

quick update: still waiting on the hardware.

khimaros commented 2 years ago

update from MonogramCC: Your pre-ordered items originally scheduled to ship out in late February will now be shipping roughly two weeks later.

khimaros commented 2 years ago

finally: Your order from Monogram is being prepared for shipment.

khimaros commented 2 years ago

device has been delivered and i've started the reverse engineering process.

unfortunately, the USB BULK protocol has changed completely from a JSON based protocol to a new binary protocol.

this is great from an efficiency perspective and probably eeks extra performance out of the embedded hardware, but it means that i need to ground-up reverse engineer and build a brand new parser for the MonogramCC devices.

as an example of the differences, PaletteGear devices used something like (ascii):

{"in":[{"i":7,"v":[0,0,0,0,0,0,0,0]}]}

and the equivalent on MonogramCC is (hexbin + "ascii"):

81 A2 "in" 94 82 A1 69 00 A1 76 98 00 00 00 00 00 00 00 00 C0 C0 C0

interpretation of layouts and screen image control, two of the more challenging parts of reverse engineering the first devices also appear to have changed somewhat.

i'll provide more info here as i discover.

khimaros commented 2 years ago

i haven't forgotten about this, but i have some bad news.

i had reverse engineered and documented about 85% of the protocol to support Monogram CC devices in ambit (~15 hours of work) and all of it was lost when the WD BLACK drive in my laptop died.

i had been lax on backups and git pushes, and ambit wasn't the only casualty.

i intend to have another go at it, but it's a very tedious process and have not made time to dive in. hopefully the second time around will take less time, but i may not be able to focus on this until September time frame.

khimaros commented 1 year ago

finally diving back into this and did a marathon reverse engineering session last night. collected a bunch of usbmon captures from the new software running in a win10 virtual machine. basically made it back to where i left off before hard drive crash.

after putting a good chunk of the spec together and mentally decoding the new binary format used for messages, i decided to do some internet searching and found that this is, in fact, msgpack. great! that should simplify things.

khimaros commented 1 year ago

a bit of a sneak peek at the new protocol decoding in action, receiving input from the MonogramCC:

[0] Searching for USB device 0483:A2C5
[0] Choosing device at USB discovery index 0.
[0] Waiting for initial layout ...
[@] BULK WRITE: b'{"start":1}'
[@] BULK WRITE: b'{"hidmap":[]}{"joymap":[]}{"midimap":[]}{"led":[]}'
[@] BULK WRITE: b'{"send_version":1}'
[@] BULK READ: b'~\x81\xa2in\x94\x82\xa1i\x00\xa1v\x98\x01\x00\x00\x00\x00\x00\x00\x00\xc0\xc0\xc0~'
[@] READ MESSAGE: {'in': [{'i': 0, 'v': [1, 0, 0, 0, 0, 0, 0, 0]}, None, None, None]}
[@] BULK READ: b'~\x81\xa2in\x94\x82\xa1i\x00\xa1v\x98\x00\x00\x00\x00\x00\x00\x00\x00\xc0\xc0\xc0~'
[@] READ MESSAGE: {'in': [{'i': 0, 'v': [0, 0, 0, 0, 0, 0, 0, 0]}, None, None, None]}
khimaros commented 1 year ago

basic LED control is now working (not yet committed/pushed):

https://user-images.githubusercontent.com/231498/201186168-caf532e8-126e-4b47-bdb3-806318a2d795.mp4

still to be done before pushing to master:

noelob commented 6 months ago

Hi @khimaros I really appreciate all the work you've put into this project! I am also experiencing the issue above, and was wondering if this work has made it into a release yet or is still a WIP?