Community Modules
QMK community modules are self-contained code packages that a keyboard turns on by
listing them in its keyboard.json. PolyKybd keeps every part of its firmware that has no
PolyKybd types and no display or protocol coupling in modules under
modules/polykybd/. That keeps those parts separate from the keyboard code and usable on
another QMK keyboard.
The modules
Section titled “The modules”| Module | What it does | Used by PolyKybd for | Tests |
|---|---|---|---|
polymod_core1 |
Starts the RP2040’s second core with its own stack, with a launch handshake that can time out; raw SIO FIFO helpers; an optional stack high-water probe (CORE1_STACK_HWM) |
The second core | none (RP2040 registers only) |
polymod_crc32 |
Table-driven CRC-32, the same checksum as zlib’s crc32() |
Split link request checks, staged image checks | none |
polymod_rle |
Decoder for the bit-run RLE overlay format; can resume mid-byte across reports | Compressed overlay uploads | none |
polymod_prc |
Decoder for PRC-coded 1-bit images: each pixel is predicted from its 10 decoded neighbours and range-coded against a fixed table. Ships PolyKybd’s table v1 and a tool to train your own | PRC overlay uploads (HID 0x29) |
make test:polymod_prc (golden vectors from the host’s encoder) |
polymod_monocypher |
Monocypher 4.0.2, unmodified: Ed25519 signature check and SHA-512 | Firmware signing | make test:polymod_monocypher (RFC 8032 test vectors) |
polymod_os_actions |
One keycode per action (“Copy”, “Lock”, “Search”), sent as the right chord for the host OS: Windows, macOS, Linux, Android, or a Ctrl-based fallback | The OS-aware action keys | make test:polymod_os_actions |
polymod_ltr559 |
Driver for the LTR-559 ambient-light and proximity sensor on I2C address 0x23; probes itself, gives up after a few tries when no sensor is fitted, keeps a rolling lux average |
Ambient-light brightness | make test:polymod_ltr559 (19 tests against a mock sensor and bus) |
All seven are licensed GPL-2.0-or-later, except Monocypher, which keeps its upstream BSD-2-Clause OR CC0-1.0 licence.
The PolyKybd policy built on top of a module stays in the keyboard code. For example,
ltr559_policy.c turns the lux reading into a display contrast and wakes the displays on
proximity; the module only reads the sensor.
Using one in your own keyboard
Section titled “Using one in your own keyboard”-
List it in your keyboard’s
keyboard.json:"modules": ["polykybd/polymod_crc32","polykybd/polymod_rle"]Listing a module is the whole enable. The build compiles
<name>/<name>.c, and definesCOMMUNITY_MODULE_<NAME>_ENABLE(for exampleCOMMUNITY_MODULE_POLYMOD_LTR559_ENABLE). Gate your own code on that define rather than inventing a second switch. -
Include its header (
polymod_crc32.h,polymod_rle.h, …) where you call it. -
Let self-driving modules run themselves.
polymod_ltr559probes the sensor in itskeyboard_post_inithook and reads it in itshousekeeping_taskhook. QMK runs module hooks before the_kband_userhooks, so by the time yourkeyboard_post_init_user()runs, the probe is done, and each housekeeping pass already has a fresh reading. Do not call the module’s init or task functions yourself as well.
polymod_core1 only works on the RP2040. polymod_ltr559 needs QMK’s I2C driver. The
other five are plain C.
Training a PRC table for your images
Section titled “Training a PRC table for your images”polymod_prc ships tools/prc_tool.py, which trains a probability table from your own
images and encodes images for the decoder. The API, the exact bitstream and the tool are
on PRC Image Decoder.
Writing a new module
Section titled “Writing a new module”A part of the firmware is worth moving into a module when it uses no PolyKybd types and
does not touch the displays, the HID protocol or the overlay stack. poly_keymap.c,
hid_com.c and the display code stay in keyboards/polykybd/.
- The fork is on community module API 1.1.2. The hooks available are listed in
data/constants/module_hooks/*.hjson. API 1.1.2 adds split transactions owned by a module (SPLIT_TRANSACTION_IDS_MODULE_<MODULE>). - If you define a module’s top-level hook yourself (for example
housekeeping_task_<module>()), callhousekeeping_task_<module>_kb()from it. Otherwise the keyboard and keymap versions of that hook never run. - A source file other than
<name>.cneeds aSRC +=line in the module’s ownrules.mk, aspolymod_monocypherdoes. - Add a unit-test suite where the module has logic worth testing. Put
TEST_LIST += <name>in the module’stests/testlist.mkand include that file frombuilddefs/testlist.mk.make test:<name>with an unregistered name exits 0 and prints nothing, so read the[ PASSED ] N tests.line rather than the exit code.