KMKfw / kmk_firmware

Clackety Keyboards Powered by Python
https://kmkfw.zulipchat.com
Other
1.38k stars 474 forks source link

Non-matrix, individual-GPIO key support, alternate RGB LED drivers #192

Closed Gadgetoid closed 2 years ago

Gadgetoid commented 3 years ago

We've been putting together an RP2040-based mech keyboard product that uses individual GPIO pins for keys in lieu of row/column scanning. From a "basic hobbyist tinkering" perspective, individual GPIOs make sense for us because they're really easy to read. It would seem they're a bit alien to the mech keyboard world, though.

RP2040 has a CircuitPython port, so it makes sense to use kmk as the go-to for firmware. However kmk is currently (and the whole mech keyboard space, perhaps?) very strongly minded toward row/col scanning.

I've been thinking carefully about how we could enhance kmk to suit our needs, without treading on any toes and- hopefully- resulting in some features that might be useful to other end users.

If we could add support for individual GPIO keyboards- perhaps by building an alternate MatrixScanner class that handles individual GPIOs under the hood - is this something you would be interested in a PR of?

We'd additionally need to support the i2c device we use to multiplex the RGB LEDs, but right now rgb is very tightly coupled into the KMKKeyboard class, with no opportunity to pass in another "LED driver". rgb seems to be exclusively for WS281x/SK6812 style pixels (NeoPixel) and while it could be modified to include support for other devices (sticking with the grain of your current LED config setup) it feels like it would fare better as a base class with the common elements, therefore I might try and:

  1. Remove any neopixel specific code from RGB into a neopixel class, subclassing rgb
  2. Add our driver as a class also subclassing RGB (might be a good time to add APA102 support, too- aka DotStar)
  3. Update KMKKeyboard to include an rgb class variable, defaulting to neopixel that specifies the driver used for RGB
  4. Use self.rgb.RGB in lieu of rgb.RGB here- https://github.com/KMKfw/kmk_firmware/blob/b8cb4bda98057bfb3fe39ac07987f7af1c75efce/kmk/kmk_keyboard.py#L249-L254
  5. self.rgb_pixel_pin could easily be a tuple providing data/clock for i2c or SPI-based pixels

That way a "board" can then add the relevant LED driver into the class variables of the KMKKeyboard subclass. This could be anything that subclasses RGB.

(Note: perhaps the default RGB functionality should be NeoPixel, to avoid name collisions and any subclass can just overload the relevant methods- ie: move the setup from __init__ to setup)

Thank you!

aerialviews007 commented 3 years ago

I mentioned it in discord that perhaps there should be support for multiple matrices. If you look at something like the ergodox, it has a single mcu with an IO expander on the opposite hand. If one were to create a similar keyboard in KMK, you list the rows and columns of both the MCU and the IO expander. While this would work, you effectively have to create one giant matrix addressing mcu/io expander key combinations that would never exist.

A better way would be to allow for multiple matricies which I believe could solve your usecase as well as each key press would be it's own matrix.

Gadgetoid commented 3 years ago

I eventually shimmed out the MatrixScanner with my own implementation that worked, and used a version of my LED control from #193 - however I was pretty quickly roadblocked by instability, and it couldn't invest any more time into it.

That code now lives in our Keybow 2040 branch - https://github.com/pimoroni/kmk_firmware/tree/keybow-2040 with pretty much the entire relevant changeset being in this commit - https://github.com/pimoroni/kmk_firmware/commit/8f82b395e1149693a28ad164b637886e40549e60 (over #193)

Notably I created a GPIOScanner that's handed to a KMKKeyboard class as a class instance rather than a class, and modified KMKKeyboard (in a somewhat questionable way) to accept an already instantiated object without trying to call its constructor. This way I could have a scanner that doesn't need to worry about any of the row/col scanning particulars.

kdb424 commented 3 years ago

https://github.com/adafruit/circuitpython/commit/b81573d43915493595759c92a4e3bd8f0fe9c10c Looks like this just merged. We could use their matrix scan for faster scans, as well as better support.

xs5871 commented 2 years ago

I believe all the feature requests in this issue have been implemented.

Anutrix commented 10 months ago

Is there a doc about individual GPIO handling?