Now Reading
Bodily knobs & userspace drivers in Elixir

Bodily knobs & userspace drivers in Elixir

2023-03-09 07:45:44

I like manufacturing gear. Audio, video and .. miscellaneous. I like issues that appear like they’ll make me oh-so-very productive. I’m a sucker prosumer as a passion. Let’s discuss Elgato, Elixir and why I by no means really get something achieved. That is sadly not sponsored by a prosumer model, or anybody, that’d have been one thing.

Advert-style pitch for a business-thing: I assist corporations discover competent, succesful or promising Elixir builders. If you happen to construct in Elixir and need to spend much less time discovering nice candidates, attain out.

Picture of my Stream Deck Plus showing some text and some custom button icons. It looks proud.

I used to be first launched to Elgato for his or her lighting panels, the arms that maintain them up and the Camlink 4K. I used to be stepping up my streaming/assembly digital camera state of affairs by placing my then solely good digital camera, a Sony ZV-1, on a stand and bettering the lighting.

On the time the digital camera didn’t do USB streaming, latest firmware permits it to do 720p.. I obtained the Elgato Camlink 4K as a substitute. It takes the HDMI out from the digital camera and lets me deal with it as a webcam through USB. It has been basically problem-free for me beneath Linux constantly. It could grasp however I’d blame my USB controllers greater than the {hardware}, different {hardware} has additionally complained.

The Elgato Keylights have been good sufficient as effectively. Hook them as much as wifi through the app, a Mac or Home windows. Then they’re accessible to be managed and so they present good subtle gentle that does the job. As I moved from Mac to Linux I began controlling them with a Python script utilizing leglight and in addition some experiments with Nerves and my very own keylight library.

I’ve been eyeing the Stream Deck as a result of all of the Mac productiveness podcasts I’ve a foul behavior of following has been hyping it up. After all. No Linux help. So I held off. Then I noticed the Stream Deck Plus which has bodily knobs. After which the Stream Deck Pedal which is a pedal. I’m not laborious to impress. Sadly.

No Linux help from Elgato however I’ve been feeling up for a problem. I checked and noticed present implementations in Python, Node, etcetera and due to this fact I thought of it doable. I’ve ported from Pyton earlier than with good outcomes. And if I obtained laborious caught it appeared like streamdeck-ui is a factor. (notice: no Stream Deck Plus help at time of writing.).

The Stream Decks are hidraw (not hello draw, hid uncooked) gadgets in Linux terminology which basically means they are often pushed with a very simplistic interface and all of the data concerning the particular machine is enshrined within the userspace code that talks to it. Just about the identical factor in different OS:es. If you’re utilizing the Stream Deck software program to set issues up, there may be actually nothing saved on the machine. The software program is polling the machine for exercise, producing and pushing new pictures each time the screens want to vary and such. Even the Stream Deck Plus with a neat number of controls and interfaces does little or no beside retain a picture and supply enter indicators.

I’d like my code to work on each Linux and the occasional Mac (I nonetheless run an Apple laptop computer) and I don’t thoughts unintentional Home windows help. Quite than work with Elixir libraries for straight hidraw I appeared for one thing utilizing the library hidapi which offers cross-platform abstractions with a easy API. I discovered hid on Hex.pm, sadly the supply repo is gone.

That is already far more elaborate than the Elgato Keylight. That’s a really straight-forward JSON API. This was tougher but in addition much more attention-grabbing.

The hidapi library offers:

  • hid_enumerate – record gadgets
  • hid_open – open a tool
  • hid_write – write an “output report” to a tool
  • hid_read – learn an “enter report” from a tool
  • hid_send_feature_report – that is one other kind of write
  • hid_get_feature_report – that is one other kind of learn
  • hid_close

There are another I don’t care about as effectively offering extra information concerning the machine and such.

The NIF library I had didn’t have all of these attached, I imagine I wanted so as to add sending characteristic studies. I think about the unique creator simply occurred to not want that. I additionally fastened the makefile to work on latest MacOS and really fastened a bug or two within the C code. As somebody who doesn’t write C, basically ever, that felt like an achievement. You may see my changes here.

These items occurred throughout the strategy of porting. I labored off of python-elgato-streamdeck as a reference implementation. Explicit props to this PR for Plus support. I additionally checked my work towards node-elgato-stream-deck a couple of occasions as I wasn’t positive the Python one had it proper. Some bizarre construct concern with dynamic shared libraries and ctypes meant I by no means really obtained the Python one operating.

The machine presents the next performance:

  • 8 buttons aka. “keys” with full colour LCD screens beneath them. Down, Up. That’s all they do.
  • An LCD touchscreen strip. 800×100, full colour. Can register quick faucet, lengthy press and a bizarre sort of drag.
  • 4 knobs, turns in steps, left, proper, also can ship a number of steps if turned rapidly. May also be pressed as a button, up/down.
  • Controllable LCD brightness (it’s actually only one panel).

All of that is achieved over that USB HID interface.

I had little or no hassle with the Elixir port general. My most long-standing wtfs the place round sending pictures to the StreamDeck and ensuring they labored. I’ve a stream of me struggling to update the LCD the place in the long run I had simply flipped two fields within the messages I used to be sending. Buttons and knobs took little or no time. In comparison with once I was making Inky over 3 years in the past I’ve written Elixir just about each day since. It’s good to really feel that the language fades away when fixing issues.

Constructing and matching binaries might have been tougher if it wasn’t for all of the work I did with The Changelog for chapter support the place I carried out an ID3v2 library for Elixir. That made me very aware of all of the binary pattern matching and constructing binaries.

Let’s even have some code in right here:

elixir
lib/streamdex/gadgets/streamdeck_plus.ex

def set_brightness(d, %) when is_integer(%) do
	% = min(max(%, 0), 100)
	payload = rightpad_bytes(<<0x03, 0x08, %>>, 32)

	write_feature(d, payload)
finish

Not too difficult. How about studying keys?

elixir
lib/streamdex/gadgets/streamdeck_plus.ex

def read_key_states(d) do
	{:okay, binary} = learn(d, 14)
	binary
finish

Additionally easy. Writing a brand new chunk of picture to the LCD is a little more concerned..

elixir
lib/streamdex/gadgets/streamdeck_plus.ex

def set_lcd_image(d, x, y, width, top, binary) do
    send_lcd_image_chunk(d, binary, x, y, width, top, 0)
finish

defp send_lcd_image_chunk(_, <<>>, _, _, _, _, _), do: :okay

defp send_lcd_image_chunk(d, binary, x, y, width, top, page_number) do
    if width + x > 800 do
      elevate "too large"
    finish

    if top + y > 100 do
      elevate "too excessive"
    finish

    bytes_remaining = byte_size(binary)
    payload_length = @config.picture.report.touchlcd_payload_length
    size = min(bytes_remaining, payload_length)

    {bytes, the rest, is_last} =
      case binary do
        <<bytes::binary-dimension(payload_length), the rest::binary>> ->
          {bytes, the rest, 0}

        bytes ->
          {bytes, <<>>, 1}
      finish

    header =
      [
        0x02,
        0x0C,
        <<x::size(16)-unsigned-integer-little>>,
        <<y::size(16)-unsigned-integer-little>>,
        <<width::size(16)-unsigned-integer-little>>,
        <<height::size(16)-unsigned-integer-little>>,
        is_last,
        <<page_number::size(16)-unsigned-integer-little>>,
        <<length::size(16)-unsigned-integer-little>>,
        0x00
      ]
      |> IO.iodata_to_binary()

    16 = byte_size(header)

    payload = header <> bytes

    payload = rightpad_bytes(payload, @config.picture.report.touchlcd_length)

    1024 = byte_size(payload)

    case write(d, payload, "set liquid crystal display picture chunk") do
      {:okay, _} ->
        send_lcd_image_chunk(d, the rest, x, y, width, top, page_number + 1)

      err ->
        err
    finish
  finish

Nonetheless not unreasonable. Simply longer.

See Also

I shared some in-progress work each in this Short and on the livestream.

The tip result’s the streamdex library which helps the Stream Deck Plus proper now in addition to the Stream Deck Pedal (actually three keys, quite simple). It’s fairly tough, alpha-level, as I solely took it to the purpose the place I might use it. When you’ve got a Stream Deck and curiosity in Elixir, be happy to contribute your machine.

As a self-taught net dev it’s wild to me that I’m writing one thing that may be pretty referred to as machine drivers proper now. I’m not claiming they’re superior or spectacular. Userspace drivers like this one dwell on prime of many layers of extra complicated implementation. I simply know that teenager me is nodding his head proper now. He’s fairly proud.

I’m additionally very glad that another person has achieved the reverse engineering. I did fireplace up Wireshark a few occasions, really how I discovered the ultimate swapped byte for the LCD, however I don’t need any credit score for determining how these work.

Ever since I obtained it absolutely operational I’ve been hacking at a crude however efficient venture for operating a bunch of my pc .. stuff. That’s also public.

To date I’ve tried:

  • Lights
    • keys for on/off
    • a knob for brightness that may be pressed for on/off
    • a knob for gentle temperature and urgent the knob resets that to a superb default
  • Calendar
    • Present present and upcoming calendar occasions on the LCD which I principally ripped from my calendar gadget eInk project. Simplistic show nonetheless, far more enjoyable available.
  • Play/Pause
    • A key that toggles and makes use of dotool to ship the media play/pause key occasion to the OS. Made a fast and nasty dotool_elixir library that pulls that collectively and compiles the Go code.
  • Mic mute
    • Each a key for toggle and a pedal for press. Sends micmute key occasion to the OS. doesn’t work at present on my KDE 🙁
  • Key icons
    • Made a small library referred to as bs_icons which pulls the Bootstrap Icons repository and offers these for me in my Elixir venture. I then mangle into keys.

Constructing on the backs of the group and ecosystem like this I’ve gotten superb mileage out of Kip Cole’s nice Image library. I’ve additionally used resvg for turning SVG into PNG, which I apparently might have achieved with Picture. On the plus aspect that additionally introduced in Rust as effectively which meant reaching fundamental hipster compliance. Now I simply want to vary my HID library to make use of Zig and I’ll have aced it. Which may occur really.

Issues but to strive:

  • Touchscreen
    • Wish to render far more attention-grabbing UI on it. Picture can accomplish that a lot enjoyable stuff and I guess I might make it play good with Brian Cardarella’s easing library. I’ve already examined a bit and Picture can replace the display at simply shy of 60hz. No concept if that appears affordable although. We will count on to push 30hz with no concern I count on. Picture offers operations like blur and ripple which I’d like to animate. I made a Short showing the silliness I’m after.
    • Utilizing the contact in any respect. I’m most curious concerning the drag. I couldn’t really see that Elgato makes use of that so it is likely to be too crap. However I need to see what I could make it do. Construct a complete little contact UI in there.
  • Replace keys whereas being pressed, set off occasions on key up after down as a substitute of down. These sorts of niceties.

It is a actually enjoyable factor to poke round with when I’ve some moments for myself. Simply making it do increasingly more. Exploring how I can mix increasingly more sources of knowledge, inputs and outputs. I’ve a really simplistic GenServer-driven strategy proper now that I’d like to consider abstracting a bit. If I need to do higher UI I must maintain the state of the UI in a different way and I’ll must handle timing for animations.

I’ve a bunch of concepts round learn how to wrap libraries that present new capabilities in a method the place they plug into this in a extra versatile method. Early ideas. Would possibly go nowhere.

Once they market macro-pads like this for productiveness I don’t assume they normally imply that you simply’ll write tons of strains of code to make them do issues. For me, this machine has made me very productive. In a really particular method.

Source Link

What's Your Reaction?
Excited
0
Happy
0
In Love
0
Not Sure
0
Silly
0
View Comments (0)

Leave a Reply

Your email address will not be published.

2022 Blinking Robots.
WordPress by Doejo

Scroll To Top