omriharel / deej

Set app volumes with real sliders! deej is an Arduino & Go project to let you build your own hardware mixer for Windows and Linux
https://deej.rocks
MIT License
4.65k stars 427 forks source link

Configurable Firmware #19

Closed jeffeb3 closed 3 years ago

jeffeb3 commented 3 years ago

Background

I think this project is great. It looks like a lot of fun, and I will end up with a pretty useful device.

I use Linux and I have some experience with 3D printing and embedded software. I have extensive experience in C++ and I've contributed to some projects like Marlin Firmware.

I see there is a vanilla firmware for 5 sliders and that seems very extensible. But I suspect a lot of people would like to stretch the capability of the arduino pro micro without writing any software.

What I'd propose we do is to write a firmware that can have it's inputs and outputs generally configurable over the serial port. This would make the firmware 20x more complicated, but we would have confidence the code would be error free (ish) and users could add an LED, a knob, or a button without editing the arduino C code.

Detailed Example

There are similar systems that I am taking inspiration from. The blink firmware, for example. Or the klipper 3D printing firmware.

The idea is that we write firmware for a specific arduino, like the arduino pro micro. In that firmware, we enable features like toggling an LED, reading a button, a knob or an encoder.

Then when the firmware connects to the golang process via serial, it is given configuration settings for which components to enable and which pins they should be enabled on.

For example, the first serial messages to the arduino might look like this:

config_add_digital_output pin=10 id=0 inverted=true
config_add_analog_input pin=A4 id=1 inverted=false
config_add_digital_input pin=9 id=2
config_send period=30

Then there might be a message like this to the firmware:

set_binary_output id=0 state=1

And the periodic status from the firmware might look like this:

1:185|2:8,8

Which would mean the id=1 had an analog value of 185, and the digital input has read 8 presses and 8 releases.

I think the firmware would be pretty easy to build for something like this. The devil is in the details. Can we easily configure a port from a String? How do we handle mistakes, like having two things with the same id? What happens when a message is lost?

The golang part (which I know very little about) would then need to be able to have that communication channel handle these flexible message lengths and be able to configure the firmware to handle whatever the user wanted.

Once we have the basics done, we can more easily add in features like having a button responsible for muting a mic, or having an LED respond to the muted state of the mic.

In the config file, I could imagine something like this:

volume:
 - pin: A4
   signal: master
 - pin: A1
   signal:
    - rocketleague.exe
    - pathofexile_x64.exe
   inverted: true
   noise_reduction: high
 - encoder: [D4, D5]
   signal:
   - spotify.exe
   resolution: 4

status:
 - pin: D6
   signal: mic.mute
 - pin: D7
   signal: master.mute

mute:
 - pin: D9
   signal: master
 - pin: D10
   signal: mic

connection:
  port: COM4
  baud_rate: 9600

Other benefits

This would mean that the firmware would stay relatively close to the same in most builds. The advantages of that are:

How do we get there?

I think this is a lot of stuff to add. I personally am most interested in defining the serial communications and writing the firmware for the arduino. But it won't work without the golang serial support. And there won't be much benefit until there are new features added to the golang software for these extra types of controls.

omriharel commented 3 years ago

Hi there @jeffeb3, thank you for your incredibly detailed write-up! I'm happy to hear you like deej.

I share a lot of the same sentiments with regard to users being able to extend the project and take full advantage of the hardware they're building with, however I do think that the way there needs to look differently. There are several main reasons in play here:

I do have a distant future plan for supporting a similar kind of extensibility in a different manner. My plan is to take advantage of code generation to build a custom firmware for the user's desired set of hardware features as selected during set-up. For example, the user would indicate that they have 5 sliders, 4 buttons and an LED ring. deej's setup would then generate a flashable firmware that supports these specific features, with pin numbers either being set manually by the user or suggested by deej, also depending on the user's choice.

This is still very far down the list of things I'm planning to add. With that being said, I have a shorter-term plan to add infrastructure-level support for handling button presses over deej's serial protocol. This would allow users to easily bind buttons to several different triggers from deej's config file. These will include triggering a keyboard shortcut, running an executable, software-muting a slider, etc. Further down the line, this can be expanded to allow advanced triggers such as making an HTTP request or even running custom Go code (via Golang's plugin system).

Here's where I might (understandably) disappoint you: I'm extremely passionate about my vision for the project and its future, but it is something I do in my free time and ultimately I would prefer to work on all of these major things by myself. I appreciate that you've put a lot of thought into your proposal, and I strongly encourage you to explore it in a fork if you're excited to do so.

I'd like to take this opportunity to sincerely apologize if this response at all strikes you as dismissive, or otherwise leaves any sort of bad taste. It is definitely not my intention. In the coming weeks, I intend to add more details about the project's development and scope to a ROADMAP file. I hope this will help people who find themselves in a similar situation down the line to manage their expectations.

I look forward to hearing your thoughts about any of the things we touched on here, and please also feel free to reach out privately to me via the project's Discord server if you prefer that.

jeffeb3 commented 3 years ago
* "does the user's config file require any knowledge about pin numbers?" - if the answer is "yes", it's too complex to put in the hands of users who e.g. receive deej as a nicely wrapped gift.

This is a really good point. I assumed the users are involved with the soldering of the project, and they would understand where the pins were on the board.

My first thought is that maybe the configuration could be layered into a hardware abstraction layer and an application layer. The hardware layer would set up slider3 and then the application layer would look a lot the same, with the config associating slider3 with the master volume.

I think we could also create good ways to handle hardware customizations we haven't thought of. By creating a well defined serial layer, which includes specific ls for custom components, makes it easier to edit, not harder. Inevitably, someone will make an led ring and someone else will have a wheel encoder and then a third person will want both. Keeping the pin assignments on the software/golang side just makes it much easier to change. But it could also be handled in the firmware. I cringe thinking that each user is making their own serial protocol and has to reinvent new customizations.

And I'm not offended at all. I really appreciate the honestly and if I sound ungrateful or critical, understand that I am just trying to express my point clearly and quickly. No worries.