Cockpit: Assessing the situation

July 13, 2024

Right, time to get this started, I am going to document my steps and thoughts so I can call myself out once I know more. This is going to be about getting to know the device and its behavior. I expect to feel like I know less at the end than when I started.

Diagnostics

Baby's first steps, I can see the lights turn on when I plug it in but I have no idea what the device looks like from the OS perspective. Let's look at what the kernel sees.

$ dmesg | grep usb
...
[   93.534289] usb 1-1: new full-speed USB device number 4 using xhci_hcd
[   93.688292] usb 1-1: New USB device found, idVendor=4098, idProduct=bed0, bcdDevice= 1.05
[   93.688309] usb 1-1: New USB device strings: Mfr=1, Product=2, SerialNumber=3
[   93.688316] usb 1-1: Product: WINWING UFC1
[   93.688321] usb 1-1: Manufacturer: Winwing
[   93.688326] usb 1-1: SerialNumber: 412340B2A416D321A3160002
[   93.725773] input: Winwing WINWING UFC1 as /devices/pci0000:00/0000:00:14.0/usb1/1-1/1-1:1.0/0003:4098:BED0.0002/input/input16
[   93.726406] hid-generic 0003:4098:BED0.0002: input,hidraw1: USB HID v1.11 Joystick [Winwing WINWING UFC1] on usb-0000:00:14.0-1/input0
[   93.726602] usbcore: registered new interface driver usbhid
[   93.726612] usbhid: USB HID core driver

It's great the manufacturer has properly named the device, I am not sure why they call it a Joystick but hey, that's a detail. What you need to take note from here is this part: idVendor=4098, idProduct=bed0. This will let us look for the device under the input devices and find its handlers.

$ cat /proc/bus/input/devices

I: Bus=0003 Vendor=4098 Product=bed0 Version=0111
N: Name="Winwing WINWING UFC1"
P: Phys=usb-0000:00:14.0-1/input0
S: Sysfs=/devices/pci0000:00/0000:00:14.0/usb1/1-1/1-1:1.0/0003:4098:BED0.0002/input/input16
U: Uniq=412340B2A416D321A3160002
H: Handlers=event14 js0
B: PROP=0
B: EV=10001b
B: KEY=1ffffff 0 0 0 0 0 0 ffff00000000 0 0 0 0
B: ABS=f8
B: MSC=10

The handler where device events are sent to event14 and we can take a peek inside it with: cat /dev/input/event14 | xxd. I am still not sure what the other handler is but I am sure we are going to find out in the future. I am piping everything through xxd because the output is binary data.

Mindless button-pressing

Standard button

So this is a single button press:

00000000: 35be 9266 0000 0000 b34d 0000 0000 0000  5..f.....M......
00000010: 0400 0400 1a00 0900 35be 9266 0000 0000  ........5..f....
00000020: b34d 0000 0000 0000 0100 c902 0100 0000  .M..............
00000030: 35be 9266 0000 0000 b34d 0000 0000 0000  5..f.....M......
00000040: 0000 0000 0000 0000 35be 9266 0000 0000  ........5..f....
00000050: 2dad 0100 0000 0000 0400 0400 1a00 0900  -...............
00000060: 35be 9266 0000 0000 2dad 0100 0000 0000  5..f....-.......
00000070: 0100 c902 0000 0000 35be 9266 0000 0000  ........5..f....
00000080: 2dad 0100 0000 0000 0000 0000 0000 0000  -...............

It's hard to show you in an article but those lines arrived at different times, 3 lines at a time. My suspicion is that they correspond to the events "key down", "key pressed", and "key up", in that order. You can also see that these packets do seem to have a standard format, there are just 2 words being changed each time to signal the different events and most of them end up being 0. That's cool, let's press it again, it's obviously going to have some very deterministic behavior and the exact same packets are gonna show up, this is easy. Here are 2 button presses of the same button because I forgot which was the first one:

00000000: a5c0 9266 0000 0000 cce8 0200 0000 0000  ...f............
00000010: 0400 0400 1a00 0900 a5c0 9266 0000 0000  ...........f....
00000020: cce8 0200 0000 0000 0100 c902 0100 0000  ................

00000030: a5c0 9266 0000 0000 cce8 0200 0000 0000  ...f............
00000040: 0000 0000 0000 0000 a5c0 9266 0000 0000  ...........f....
00000050: a50b 0500 0000 0000 0400 0400 1a00 0900  ................

00000060: a5c0 9266 0000 0000 a50b 0500 0000 0000  ...f............
00000070: 0100 c902 0000 0000 a5c0 9266 0000 0000  ...........f....
00000080: a50b 0500 0000 0000 0000 0000 0000 0000  ................

00000090: a6c0 9266 0000 0000 776f 0d00 0000 0000  ...f....wo......
000000a0: 0400 0400 1a00 0900 a6c0 9266 0000 0000  ...........f....
000000b0: 776f 0d00 0000 0000 0100 c902 0100 0000  wo..............

000000c0: a6c0 9266 0000 0000 776f 0d00 0000 0000  ...f....wo......
000000d0: 0000 0000 0000 0000 a7c0 9266 0000 0000  ...........f....
000000e0: ab77 0000 0000 0000 0400 0400 1a00 0900  .w..............

000000f0: a7c0 9266 0000 0000 ab77 0000 0000 0000  ...f.....w......
00000100: 0100 c902 0000 0000 a7c0 9266 0000 0000  ...........f....
00000110: ab77 0000 0000 0000 0000 0000 0000 0000  .w..............

Uh... those are not the same at all. Let's do 2 more of the same:

00000000: f9c0 9266 0000 0000 0120 0600 0000 0000  ...f..... ......
00000010: 0400 0400 1a00 0900 f9c0 9266 0000 0000  ...........f....
00000020: 0120 0600 0000 0000 0100 c902 0100 0000  . ..............

00000030: f9c0 9266 0000 0000 0120 0600 0000 0000  ...f..... ......
00000040: 0000 0000 0000 0000 f9c0 9266 0000 0000  ...........f....
00000050: df42 0800 0000 0000 0400 0400 1a00 0900  .B..............

00000060: f9c0 9266 0000 0000 df42 0800 0000 0000  ...f.....B......
00000070: 0100 c902 0000 0000 f9c0 9266 0000 0000  ...........f....
00000080: df42 0800 0000 0000 0000 0000 0000 0000  .B..............

00000090: fac0 9266 0000 0000 6b58 0700 0000 0000  ...f....kX......
000000a0: 0400 0400 1a00 0900 fac0 9266 0000 0000  ...........f....
000000b0: 6b58 0700 0000 0000 0100 c902 0100 0000  kX..............

000000c0: fac0 9266 0000 0000 6b58 0700 0000 0000  ...f....kX......
000000d0: 0000 0000 0000 0000 fac0 9266 0000 0000  ...........f....
000000e0: 527b 0900 0000 0000 0400 0400 1a00 0900  R{..............

000000f0: fac0 9266 0000 0000 527b 0900 0000 0000  ...f....R{......
00000100: 0100 c902 0000 0000 fac0 9266 0000 0000  ...........f....
00000110: 527b 0900 0000 0000 0000 0000 0000 0000  R{..............

Crap, every time it's different. There must be some state affecting it... Right, well that's a puzzle for later, certainly an interesting one! Let's do some more experimenting, time to try one of the switches and one of the knobs.

Knobs

The knobs are actually pretty sensible, at specific points in their rotation they will emit a single packet. Those packets also seem to have some state and differ at each step but that's sort of expected, here are 2 packets:

00000000: fdc1 9266 0000 0000 c2a7 0a00 0000 0000  ...f............
00000010: 0300 0300 1e00 0000 fdc1 9266 0000 0000  ...........f....
00000020: c2a7 0a00 0000 0000 0000 0000 0000 0000  ................

00000030: fdc1 9266 0000 0000 7c55 0c00 0000 0000  ...f....|U......
00000040: 0300 0300 1f00 0000 fdc1 9266 0000 0000  ...........f....
00000050: 7c55 0c00 0000 0000 0000 0000 0000 0000  |U..............

Again, very specific words changing, what's odd is that the same are changing in the button packets... That's odd, another puzzle.

Switches

Switches are going to be like buttons though, I mean, how much can they differ? Apparently quite a bit... Once plugged in and a switch is in the neutral position then it emits no signal, so far so good. But once you flick it either way it keeps emitting packets, yes every time they are also slightly different. When you flick it back to neutral it still emits packets at a rapid rate until you press another button... So in any position a switch will keep emitting packets until another button is pressed but if a knob is turned then the packets get multiplexed and you have a stream of both coming up.

LEDs

I will be ignoring the fact that there are LEDs I can control until I have input sorted out. There is already a lot of stuff going on so we will be coming back to this later!

What's next?

In theory we just pressed some buttons but this is actually a lot of information and quite a few short-term goals are becoming clearer. To recap, we learned that:

  • there are structured packets, each packet has a length of 48-bytes
  • identical actions do not produce identical data, there must be some state mixed in there
  • buttons do seem to follow the web-standard for input events
  • each type of button has its own behavior, sometimes affected by other buttons

The next thing I want to tackle is being able to identify which button is being pressed. If I can figure out why the packets change that's even better but I would be willing to settle for just identifying the button and ignoring the rest for now. There are 2 things in my mind to tackle this, the first is to play a bit more with the buttons while looking at the packets, maybe look at their binary representation until I can identify some pattern. If that doesn't pan out, I have to assume that developers followed some sort of good USB-related practices that could explain this. I have no clue if such a thing even exists but it might be worth having a look just in case this is in-fact very standard behavior that I don't understand because I lack the background.