Rotary Trinkey - HID Keyboard messages failing on recording device, but code working on Windows

Hi all,

I'm trying to program the Adafruit Rotary Trinkey to send HID messages to a Sound Devices Mixpre 10II recorder for controlling volumes.

The code itself works as expected on Windows both through the Arduino IDE code and Circuit Python Code without any issues. However, the device I'm trying to use this for isn't getting these messages despite working with other standard USB keyboards. The Arduino version boots but the unit never responds to the HID messages while the Circuit Python Code fails as soon as a message is sent and goes into two red blink mode (Ended with exception).

I've read others have trouble here because the USB Descriptor for the Mixpre is unique and they had trouble getting it to recognize the chip. However, there is a working arduino controller out there for the MixPre so I know there is some Arduino solution here I don't know about.

Is anyone familiar with working around issues with USB Descriptors to allow communication with tricky devices that you can't easily connect to and debug? Perhaps it requires a custom HID program and using voltages instead of relying on USB_HID or HID-Project? Clearly there is something wrong with the handshake between this Rotary Trinkey and this specific device and I'm hoping someone with experience here can lead me to the right solutions.

Here was a previous post that ended up unresolved discussing this: Rotary Encoder confusion - #5 by encodurrr

None of the following made it work with the mixpre: Bootkeyboard and keyboard both fail to send, delays didn't help it recognize the device, US and ASCII layouts both failed, trying write or press calls had no effect.

Here is a previous forum post that went unresolved.
CIRCUIT PYTHON CODE:

import time

import rotaryio import digitalio import board import neopixel import usb_hid import touchio

from adafruit_hid.keyboard import Keyboard

from adafruit_hid.keycode import Keycode from adafruit_hid.keyboard_layout_us import KeyboardLayoutUS

# Windows mouse test

from adafruit_hid.mouse import Mouse mouse = Mouse(usb_hid.devices)

# time.sleep(.5)

usb_hid.enable((usb_hid.Device.KEYBOARD,))   # Enable just KEYBOARD now in boot

touch = touchio.TouchIn(board.TOUCH)

pixel = neopixel.NeoPixel(board.NEOPIXEL, 1, brightness=1.0) encoder = rotaryio.IncrementalEncoder(board.ROTA, board.ROTB)

switch = digitalio.DigitalInOut(board.SWITCH)

switch.switch_to_input(pull=digitalio.Pull.DOWN)

kbd = Keyboard(usb_hid.devices)

keyboard_layout = KeyboardLayoutUS(kbd)

print("Success")



switch_state = None

touch_state = None last_position = encoder.position

while True:

time.sleep(.1) # .1 feels smoother visually, .02 is seizure inducing

pixel.fill((50, 50, 50)) # Default low white

current_position = encoder.position

position_change = current_position - last_position

if position_change > 0:

    for _ in range(position_change):

        kbd.send(Keycode.UP_ARROW)  # Windows functional up arrow.

        # kbd.send(0x60)  #  Raw HID works on windows, fails mixpre as well

        # kbd.press(Keycode.UP) # Wrong message

        # kbd.release_all()

        #mouse.move(1, 1, 0) # mouse right movement and up

        pixel.fill((0, 255, 255)) # Purple

        print(f"rotate A:{current_position}, switch:{switch.value}")

        print(f"rotate A:touch:{touch.value}")

elif position_change < 0:

    for _ in range(-position_change):

        kbd.send(Keycode.DOWN_ARROW)  # Windows functional down arrow.

        # kbd.send(0x5A) #  Raw HID works on windows, fails mixpre as well

        # kbd.press(Keycode.DOWN) # Wrong message

        # kbd.release_all()

        # mouse.move(1, 1, 0) # mouse left movement and up

        pixel.fill((180, 0, 250)) # Blue

        print(f"rotate B:{current_position}, switch:{switch.value}")

        print(f"rotateB:touch:{touch.value}")

last_position = current_position

if not switch.value and switch_state is None:

    switch_state = "pressed"

if switch.value and switch_state == "pressed":

    print("switch pressed.")

    kbd.send(Keycode.ENTER)

    pixel.fill((255, 99, 16)) # orange

    time.sleep(.2) # Extra delay for visual accuracy on confirmation

    switch_state = None

if not touch.value and touch_state is None:

    touch_state = "pressed"

    mouse.release(Mouse.LEFT_BUTTON) #Release

if touch.value and touch_state == "pressed":

    print("Pad touched!")

    kbd.send(Keycode.ESCAPE)

    # mouse.click(Mouse.LEFT_BUTTON) single press

    # mouse.press(Mouse.LEFT_BUTTON) #Press and hold mouse left. Ignores plugins popups somehow

    pixel.fill((255, 255, 0)) # yellow

    time.sleep(.08) # Extra delay for visual accuracy

    touch_state = None

ARDUINO CODE

#include <Adafruit_NeoPixel.h>

#include <Adafruit_FreeTouch.h>

#include <RotaryEncoder.h>

#define HID_CUSTOM_LAYOUT

#define LAYOUT_UNITED_KINGDOM

#include <HID-Project.h>

//#include <Keyboard.h>

//#include <KeyboardButton.h>

#define PIN_ENCODER_A 1

#define PIN_ENCODER_B 2

#define PIN_ENCODER_SWITCH 3



// Create the neopixel strip with the built in definitions NUM_NEOPIXEL and PIN_NEOPIXEL

Adafruit_NeoPixel strip = Adafruit_NeoPixel(NUM_NEOPIXEL, PIN_NEOPIXEL, NEO_GRB + NEO_KHZ800);

int16_t neo_brightness = 22; // initialize with 22 brightness (out of 255)



RotaryEncoder encoder(PIN_ENCODER_A, PIN_ENCODER_B, RotaryEncoder::LatchMode::FOUR3);

// This interrupt will do our encoder reading/checking!

void checkPosition() {

encoder.tick(); // just call tick() to check the state.

}



uint8_t wheel_offset = 99;

int last_rotary = 0;



void setup() {

//USBDevice.detach();

//Serial.end();

//BootKeyboard.begin();

Keyboard.begin();

//Serial.begin(115200);

//Serial failed with 9600 115200 and 250000

//while (!Serial);



// start neopixels

strip.begin();

strip.setBrightness(neo_brightness);

strip.show(); // Initialize all pixels to 'off'



attachInterrupt(PIN_ENCODER_A, checkPosition, CHANGE);

attachInterrupt(PIN_ENCODER_B, checkPosition, CHANGE);

// set up the encoder switch, which is separate from the encoder

pinMode(PIN_ENCODER_SWITCH, INPUT_PULLDOWN);



}



void loop() {

// read encoder

int curr_rotary = encoder.getPosition();

RotaryEncoder::Direction direction = encoder.getDirection();

//delay test

delay(10);



if (curr_rotary != last_rotary) {

Serial.print("Encoder value: ");

Serial.print(curr_rotary);

Serial.print(" direction: ");

Serial.print((int)direction);



// behavior differs if switch is pressed

if (!digitalRead(PIN_ENCODER_SWITCH)) {

// update color

if (direction == RotaryEncoder::Direction::CLOCKWISE) {

wheel_offset++;

Keyboard.write(KEY_UP_ARROW);

//BootKeyboard.write(HID_KEYBOARD_UPARROW);

//Keyboard.press(KEY_UP_ARROW);  //Press needs release all but write handles both messages

delay(50);

//Keyboard.releaseAll();

}

if (direction == RotaryEncoder::Direction::COUNTERCLOCKWISE) {

wheel_offset--;

Keyboard.write(KEY_DOWN_ARROW);

//BootKeyboard.write(HID_KEYBOARD_DOWNARROW);

//Keyboard.press(KEY_DOWN_ARROW);

delay(50);

//Keyboard.releaseAll();

}

} else {

// update brightness

if (direction == RotaryEncoder::Direction::CLOCKWISE) {

neo_brightness += 10;

}

if (direction == RotaryEncoder::Direction::COUNTERCLOCKWISE) {

neo_brightness -= 10;

}

// ranges between 0 and 255

if (neo_brightness > 255) neo_brightness = 255;

if (neo_brightness < 0) neo_brightness = 0;

}

Serial.print(" wheel color: ");

Serial.print(wheel_offset);

Serial.print(" brightness: ");

Serial.println(neo_brightness);



last_rotary = curr_rotary;



// update pixels!

strip.setBrightness(neo_brightness);

strip.setPixelColor(0, Wheel(wheel_offset));

strip.show();

}

}



// Input a value 0 to 255 to get a color value.

// The colours are a transition r - g - b - back to r.

uint32_t Wheel(byte WheelPos) {

if(WheelPos < 85) {

return strip.Color(WheelPos * 3, 255 - WheelPos * 3, 0);

} else if(WheelPos < 170) {

WheelPos -= 85;

return strip.Color(255 - WheelPos * 3, 0, WheelPos * 3);

} else {

WheelPos -= 170;

return strip.Color(0, WheelPos * 3, 255 - WheelPos * 3);

}

}

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.