trireme_fm1, image 1 from its README
1/6
Firmware

trireme_fm1

Rising71/100

VIAL compatible macros keyboard firmware for Mvave FM1

trireme_fm1 is custom firmware for the M-VAVE FM-1, by @ignis32. Open source under GPL-3.0, latest release v0.1.1 (October 2026), 4 stars on GitHub.

forM-VAVE FM-1·by@ignis32

Unclaimed. Is this yours? Sign in with GitHub as @ignis32 to claim it.

Downloads
0
Stars
4
Forks
0
Commits
6
Last commit
Download v0.1.1

trireme-fm1-v0.1.1.fwsc· 596 KB· +3 files

GPL-3.0· ignis32/trireme_fm1·downloads come from the creator’s GitHub releases

6
Commits
2
Releases
6 commits and 2 releases in the last year
Activity · last 12 months

Trireme FM-1

[!WARNING] This firmware is vibe-coded: it was written with an AI coding assistant. I use it on my own FM-1, but I have not been able to test every function by hand. Expect rough edges, and keep the stock firmware at hand.

Custom firmware that turns the M-VAVE FM-1 into a programmable USB keyboard and macro pad, configured with Vial or directly on the device.

The main screen: the layer, the USB state and what every control does The on-device editor: assigning Ctrl+C to a button The on-device editor: Space when tapped, layer 2 while held

Unofficial. Not affiliated with or endorsed by M-VAVE. Installing custom firmware is at your own risk. The FM-1 can always go back to the stock firmware (see Going back to stock).

What it does

  • Every note key, button and the four right-hand knobs can send any key: letters, symbols, F-keys, numpad, arrows, shortcuts with modifiers (Ctrl+C, Alt+Tab, ...).
  • Media and mouse keys: volume, play / pause, next / previous, mouse movement, buttons and wheel.
  • Five layers, like any QMK keyboard: keys that switch layers while held, for one key press, or until pressed again; layer-tap (a key that types when tapped and switches a layer when held), mod-tap, one-shot modifiers.
  • Macros, tap dance, combos and the QMK timing settings, edited in Vial.
  • Vial support: the keyboard shows up in the Vial app and on vial.rocks with its own layout; no definition file to load.
  • An on-device editor: change any key, knob and light without a computer.
  • A live legend on the screen: the FM-1's printed labels mean nothing as a keyboard, so the screen always shows what each control does on the current layer.
  • Per-key lights: each button and key has a light style per layer (off, dim, mid, on, breathe, blink), or automatic (brighter for modifiers, layers and macros).
  • The configuration is kept in the FM-1's flash and survives power cycles and reinstalls of the stock firmware.
  • It stays a USB-MIDI device too, so the usual firmware installers keep working.

Installing

  1. Install the stock V15 firmware first. The FM-1 community's rule: always go back to stock V15 before installing a different custom firmware. Get it from M-VAVE (FM-1.fwsc) and install it with M-VAVE's updater or the installer below.

  2. Download the latest trireme-fm1-v<version>.fwsc from the Releases page.

  3. Install it like any FM-1 firmware package. With felucca-bsp's installer (Python 3, pip install mido python-rtmidi; on Linux you may need sudo for MIDI access):

    python3 fm1_install.py trireme-fm1-v0.1.1.fwsc
    

    The installer is in this repository at third_party/felucca-bsp/tools/fm1_install.py.

    Release packages are built on GitHub from the tagged source by The Firmware Hub's shared workflow, which signs a build attestation (provenance). To check that a package is exactly the one built from this repository (needs the GitHub CLI):

    gh attestation verify trireme-fm1-v0.1.1.fwsc --repo ignis32/trireme_fm1 \
        --signer-workflow zvenson/fm1-build/.github/workflows/build.yml
    
  4. The FM-1 restarts as FM-1 Keyboard. The screen says READY when the computer has accepted it.

Going back to stock

Install the stock V15 package the same way. The keyboard configuration stays in flash, untouched, for the next time.

The method I actually use to get back to stock reliably is the installer on Baud Girl's website (Chrome or Edge).

If the firmware ever does not start: hold OCT+ while powering on (or hold OCT- and OCT+ together for 10 seconds while it runs). The FM-1 enters update mode and accepts any firmware package. After two failed starts in a row it enters update mode by itself.

The controls

Main screen, buttons and knobs page Main screen, note keys page

ControlWhat it does
Note keys, FX ... EDIT, GLO, HOME ... REC, KNOB1-4Yours to assign (keys, shortcuts, media, mouse, layers, macros, ...)
PRESETSSwitches the layer (0-4)
SELECTFlips the legend between the buttons and knobs page and the note keys page
OCT+Opens the editor
OCT- + OCT+ held 2 sUnlocks Vial, when Vial asks
OCT- + OCT+ held 10 sUpdate mode
OCT- held at power-onMIDI only: no keyboard on USB
OCT+ held at power-onUpdate mode

The screen shows the layer, the USB state and the legend. The last control you used is highlighted for two seconds and its full meaning is shown below the legend.

Default layout (layer 0)

ControlsKeys
Note keys, lowest to highestA ... Z, then Space
FX ... REC (12 buttons)F13 ... F22, PLAY = play / pause, REC = F24
KNOB1Volume
KNOB2Mouse wheel
KNOB3Left / right arrow
KNOB4Down / up arrow

Layers 1-4 start empty: every control falls through to layer 0.

Configuring with Vial

Open the Vial app or vial.rocks in Chrome or Edge with the FM-1 connected. It finds FM-1 Keyboard and shows its layout. Everything is saved to the FM-1 a few seconds after the last change.

To change macros (or assign the bootloader key), Vial asks to unlock the keyboard: hold OCT- and OCT+ together for 2 seconds (a bar fills on the screen).

Unlocking Vial: hold OCT- and OCT+

On Linux, Vial needs a udev rule to see the keyboard (the standard one from the Vial docs):

export USER_GID=`id -g`; sudo --preserve-env=USER_GID sh -c 'echo "KERNEL==\"hidraw*\", SUBSYSTEM==\"hidraw\", ATTRS{serial}==\"*vial:f64c2b3c*\", MODE=\"0660\", GROUP=\"$USER_GID\", TAG+=\"uaccess\", TAG+=\"udev-acl\"" > /etc/udev/rules.d/99-vial.rules && udevadm control --reload && udevadm trigger'

The FM-1's own functions are custom keycodes in Vial's User tab: LAYER- and LAYER+ (step through the layers) and KB OFF (stops sending keys to the computer; press it again to turn them back on).

The on-device editor

Press OCT+. The hint line at the bottom always says what OCT- and OCT+ do next.

1. Choose a control. Press any key or button, or turn a knob in the direction you want to change. It is highlighted and its current meaning is shown. PRESETS picks the layer to edit. SELECT picks what to do with it:

ActionWhat it does
EDITChange it (the default)
COPY / SWAPCopy it to, or swap it with, another control
CLEARMake it empty (falls through to the layers below)
DEFAULTBack to the default layout
COPY LAYER / CLEAR LAYERThe whole layer at once
INFOFirmware version, the number of saves, the configuration size
LED TESTEvery light on

OCT+ does it, OCT- leaves the editor.

Choosing a control: REC is selected

2. Edit it. The screen becomes a grid of values:

  • PRESETS: the category (letters and digits, symbols, edit / navigation, F-keys, numpad, media, mouse, layers, macros, tap dance, FM-1, ...).
  • SELECT: moves up and down through the grid (and its pages).
  • ALGORITHM: moves across.
  • The white note keys jump straight to a page of the grid; the lit ones have a page.

The buttons become tools, labelled in the two strips at the top of the screen:

ButtonsIn the editor
FX SEL ENV LFO EDITCtrl, Shift, Alt, GUI (Windows / Command key), Right (use the right-hand modifiers)
GLOMode: WITH (modifiers held with the key), HOLD (the key when tapped, the modifiers when held), ONE-SHOT (the modifiers apply to the next key), LAYER (the key when tapped, a layer when held: FX ... EDIT then pick layer 0-4)
HOME ... RECLight: OFF, DIM, MID, ON, BREATHE, BLINK; press the selected one again for automatic

The control's own light previews the light style you pick. The line under the grid says the result in words ("CTRL+C", "TAP SPACE HOLD L2"), or why a combination cannot be saved.

OCT+ saves, OCT- cancels. Both go back to step 1.

Ctrl+C on REC Space when tapped, layer 2 when held

Layer keys (category LAYERS): HOLD (the layer while the key is held), ONE-SHOT (for the next key press), GO TO (switch to it), TOGGLE (switch to it until the same key is pressed again).

What the editor cannot do: write macros, tap dances and combos, or change the QMK timing settings. It can assign existing macros and tap dances to keys; use Vial to write them. Anything set in Vial that the editor cannot show is kept as it is.

Building

You need Linux (or WSL), make, GCC (for the PC tests), Python 3, and:

  • The JieLi Linux toolchain: jieli-linux-toolchains (tested with 20250324.1 and 20260730.1: both give the same package). Unpack it; TC is the directory with pi32v2/ and common/ in it.
  • The JieLi AC79 SDK (Apache-2.0), only for building the package: felucca-bsp's tools/get_sdk.sh fetches the tested revision into ~/.jieli/ac79-sdk.
git clone --recursive https://github.com/ignis32/trireme_fm1
cd trireme_fm1
third_party/felucca-bsp/tools/get_sdk.sh             # the SDK, into ~/.jieli/ac79-sdk
make package TC=/path/to/jieli-linux-toolchains      # build/fw-raw/fm1kbd-raw.fwsc
make release                                         # build/release/: trireme-fm1-v$(VERSION).fwsc + SDK licence
make test                                            # the tests on the PC
make screens                                         # the screen pictures as PNGs (needs Pillow)

Put TC := ... and AC79_SDK := ... in a local.mk file to avoid typing them. The default TC is ~/.jieli/toolchain.

make test runs the USB descriptor checks, the key engine and Vial protocol tests, the flash storage tests (including power cuts at every step of a save) and the screen and editor tests. With a checkout of vial-gui in refs/vial-gui it also drives the firmware's Vial code with vial-gui's own protocol code.

FLAVOR=console builds a variant with a USB serial console instead of Vial, for development.

Releases

Releases are never built or uploaded by hand. Set VERSION in the Makefile, commit, and push the tag v$(VERSION): .github/workflows/release.yml hands the build to zvenson/fm1-build @v1, which runs make release and make test, attests the files in build/release/ and publishes them as the tag's release. Running the workflow by hand (Actions → release → Run workflow) builds and attests without releasing.

Layout

PathWhat
firmware/main.cBoot, the main loop, LEDs, screen hooks
firmware/kbcore.cThe key engine (layers, tap / hold, combos, macros) and the Vial protocol
firmware/store.cThe configuration in flash (two copies, power-cut safe)
firmware/editor.c, ui.c, gfx.cThe on-device editor, the screens, the drawing
firmware/usb.cfelucca-bsp's USB driver with HID added (patches/usb-hid.patch)
firmware/vial.jsonThe Vial definition (built into the firmware)
tests/The PC tests
tools/Build helpers, vialcli.py (keys and macros from the command line)
third_party/felucca-bspThe FM-1 board support (git submodule)

Licence and credits

GPL-3.0 (LICENSE). The firmware includes felucca-bsp's usb.c, which is GPL-3.0-only.

felucca-bsp's licensing is not final. It is being split out of Felucca, and its own LICENSING.md says the licences are provisional until every contributor involved has answered. The intended licences are MPL-2.0 for most files and GPL-3.0-only for usb.c. This firmware is GPL-3.0 as a whole, which fits either outcome, but the state of felucca-bsp's files may change.

  • felucca-bsp by Leo Kuroshita / Hügelton Instruments (MPL-2.0, usb.c GPL-3.0-only), split out of Felucca: chip and board support, the update loader, the package builder and installer.
  • Spleen fonts by Frederic Cambus (BSD-2-Clause, notice in firmware/font.h).
  • Keycode numbers from vial-qmk (QMK / Vial protocol).
  • Firmware packages contain three files of the JieLi AC79 SDK (Apache-2.0); its licence text goes with every released package.