Skip to content

Differences by firmware

This page says which wire behavior was measured on which keyboard and module firmware, what the vendor's release notes say changed in each version, and what halves on different firmware do. The one thing to know first: read fe/1002 on both halves before following any recipe on this site, because several behaviors (three-frame writes, the second keymap bank, the Bluetooth status commands) differ between versions, and a mismatched pair behaves unlike either.

At a glance

  • fe/1002 replies 00 00 <major> <minor> <patch>: 3.41.0 is 00 00 03 29 00, 3.35.4 is 00 00 03 23 04.
  • 3.28.7 wedges on any three-frame write and has no be/100c to be/100f; 3.41.0 accepts both.
  • Three keyboard versions shipped only on the beta channel: 3.39.4, 3.40.0 and 3.40.4.
  • Halves on different firmware still type, but the peripheral's LEDs go dark and its own port answers empty payloads.
  • A firmware flash keeps the Bluetooth bonds and the keymap; re-send the LED ceiling afterwards.

A cell that says "not recorded" means nobody we know of measured it. MEASURED means measured on the owner's boards (a 3.41.0 board and a donor board on 3.28.7) unless a source is named.

Read the version first

Read fe/1002 on each half before anything else (params 00). The reply is 00 00 <major> <minor> <patch>: 3.41.0 is 00 00 03 29 00, 3.35.4 is 00 00 03 23 04, and 3.30.1 is 00 00 03 1e 01. The vendor writes the same firmware as v0.3.29.1 in some notes and 3.29.1 in others (the NayaFlow 1.14.5 notes say 0.3.28.7, the 1.15.0 notes say 3.29.1), so the reply's leading 00 is the vendor's leading 0; Versions explains the four-part form once. MEASURED 3.41.0, 3.35.4 (2026-09-20) REPORTED (3.30.1)2 DOC7

Before you follow a recipe

Send aa 00 50 00 fe 03 10 02 00 12 04 on the left half's port and aa 00 51 00 fe 03 10 02 00 12 04 on the right half's port (both read-only). If the two versions differ, fix that first (see below and Flashing). The module's own version is de/1008; the module bundle stored on the keyboard is de/100a (see Modules).

Which versions exist

Keyboard firmware, by the first release that carries the image (the image itself, not the release note). Beta images carry no readable version, so each beta version is named by its strongest witness (the same bytes as a known image, NayaCore's version literal, the app's firmware constant) before the release note.

Keyboard firmware Channel First release carrying it fe/1002 reply Evidence
3.28.7 stable NayaFlow 1.14.5 00 00 03 1c 07 STATIC (image) INFERRED (bytes)
3.29.1 stable 1.15.0; also betas 1.16.0, 1.16.1 and 1.17.0, which ship the stable 1.15.x images byte for byte although the 1.16.0 note announces 3.31.1 00 00 03 1d 01 STATIC INFERRED (bytes)
3.30.1 none in no public release on either channel (the nayactl maintainer's board; a factory build is the likelier reading) 00 00 03 1e 01 REPORTED2 INFERRED (origin)
3.31.1 beta, then stable beta 1.17.1 (2026-02-11); stable 1.17.2 00 00 03 1f 01 STATIC INFERRED (bytes)
3.35.4 beta, then stable beta 1.18.0 (2026-03-12) through beta 1.21.0; stable 1.19.1 (2026-04-03) 00 00 03 23 04 STATIC MEASURED 2026-09-20
3.39.4 beta only beta 1.22.0 (2026-05-18); its release note says 3.39.3, but the app's firmware constant and NayaCore's version string both say 3.39.4 00 00 03 27 04 STATIC DOC INFERRED (bytes)
3.40.0 beta only beta 1.23.0 (2026-05-21) and 1.23.1 00 00 03 28 00 STATIC INFERRED (bytes)
3.40.4 beta only beta 1.24.0 (2026-06-09) 00 00 03 28 04 STATIC INFERRED (bytes)
3.41.0 both 1.25.0 on both channels (2026-07-17); beta 1.25.0 carries generations A and B 00 00 03 29 00 STATIC MEASURED 2026-09-01

Beta 1.10.0 carries no firmware. Every beta image before 1.25.0 is generation A only; all beta images use the stable signing key hash and the same pre-armed permanent-swap trailer (MCUboot header version 1.2.3+4). DOC STATIC89 The fe/1002 bytes for versions nobody has read follow the encoding above and are not measured. Generations, signing and the trailer are explained on Images.

Module firmware, by the first release that carries the bundle:

Module firmware First release carrying it Notes Evidence
2.1.1 NayaFlow 1.14.3 STATIC
2.1.2 1.14.5 (with keyboard 3.28.7) measured on our donor board's modules and on a right-docked Touch of the 3.41.0 board STATIC MEASURED
2.2.0 1.15.x; also betas 1.16.0 to 1.17.0, although the 1.16.0 note announces 2.3.2 STATIC DOC
2.2.2 in no public release on either channel measured on the nayactl maintainer's modules, with keyboard 3.30.1 REPORTED2
2.3.2 beta 1.17.1; stable 1.17.2 to 1.21.0; beta 1.22.0 still carries it STATIC
2.3.3 beta 1.23.0; stable 1.25.0 the Tune and Track on the 3.41.0 board STATIC MEASURED

The version bytes read by de/1008 and de/100a follow the keyboard's scheme: de/100a answers 00 00 02 03 03 for 2.3.3. MEASURED 3.41.0, 2026-09-16 DOC (the bundle's LittleFS VERSION file)8

Minimum firmware per command

NayaCore 6.11.0 checks each board against minimum keyboard firmware versions, per operation and per command. The values are readable in the binary: inline string variables set at start-up from literals such as 0.3.30.0 STATIC6. In short: 3.30.0 for REMAP and most operations, 3.32.0 for be/100c-be/100f, 3.34.0 for be/1010 and 3.36.0 for fe/100a / fe/100b. Per command, for the Create halves:

Commands Minimum keyboard firmware Note
30/1001-30/100e, 30/10ca 3.30.0 left half only ("Unsupported" on the right)
be/1001-be/100b 3.30.0
be/100c-be/100f 3.32.0 BLEStatus; be/100c is "Unsupported" on the right half
be/1010 3.34.0 ClearAllSplitLinks
de/1001-de/100b except de/1004 3.30.0
ed/1003-ed/1011, ed/10d1, ed/10d2, ed/1050 3.30.0 ed/1012-ed/1014 are "Unknown" to the table
ee/10ae, ee/10be, ee/10ce 3.30.0
fa/1001, fa/1002, fa/1006 3.30.0
fe/1001-fe/1009 3.30.0
fe/100a, fe/100b 3.36.0 ActivityTimeouts
all ca/* and f1/* 3.30.0

Per operation: Keymap, Pair, ClearAllData, TestSPIFlash and UpdateModule need 3.30.0 (copies of the ProtocolCDC minimum), BLEStatus 3.32.0, and UpdateFW has no minimum (0.0.0); Keymap, ClearAllData and UpdateModule apply to the left half only. Modules need 2.3.0 for their ProtocolCDC and the dongle 0.1.0.2 (as written) STATIC6.

These are the host's gates, not a list of what older firmware can do: 3.28.7 answers REMAP reads although its gate is 3.30.0, while its missing be/100c-be/100f fits the 3.32.0 gate MEASURED 2026-09-19. How NayaCore acts on a board below a gate (refusal or warning) is OPEN (details). The same tables are on Versions; how they were read is on Disassembly.

Behavior by keyboard firmware

Each cell is tagged; "not recorded" means nobody we know of measured it.

Behavior 3.28.7 3.30.1 3.35.4 3.39.4 to 3.40.4 (beta) 3.41.0
CDC interfaces per half two (right MI_00 + MI_02, left MI_00 + MI_03), one serial, only one answers MEASURED 2026-09-19 not recorded not recorded not recorded one (MI_00) MEASURED
be/100c to be/100f no frame at all, both halves MEASURED 2026-09-19 not recorded "BLE v2" arrives DOC not recorded answered; be/100f replies 00 02 MEASURED
Three-frame writes wedge the half until unplugged (three-chunk reads are fine) MEASURED 2026-09-19 not recorded not recorded not recorded NayaFlow's three-frame writes accepted MEASURED 2026-09-01
Second keymap bank on 30/1003 not recorded not recorded never returned; reads stop at position 51 MEASURED 2026-09-21/22 not recorded returned, padded with 07 00 (156 records) on our board even for layers with no second-bank record MEASURED 2026-09-01; 82 records per layer, for layers that apparently never held a second-bank record, in a third-party capture REPORTED (raw data checked)13
LED data between the halves not recorded not recorded differs from 3.41.0: a 3.41.0 left with a 3.35.4 right leaves the right half's LEDs dark MEASURED 2026-09-20/22 not recorded see the 3.35.4 cell
LED-map read of a layer with no map status 16 with a header only; the layer renders uniformly white until a map is written MEASURED 2026-09-19 not recorded not recorded not recorded status 16 in a third-party capture REPORTED (raw data checked)13
Macro opcodes 30/1005 to 1008 status 11 (not implemented) MEASURED 2026-09-19 not recorded not recorded not recorded writes acked and nothing kept (2026-09-07); the one captured list read (params 00) answered status 11 (2026-09-01) MEASURED
Text channel (SystemCDC) untested answered REPORTED1 untested retired since 3.31.1 DOC7 zero bytes on both halves MEASURED 2026-09-01
30 s floor on activity timeouts (status ea below it) not recorded not recorded not recorded timeout controls first shipped with 3.39.4; 3.40.4 fixed three timeout bugs DOC9 measured MEASURED 2026-09-11

NayaCore never sends the macro opcodes (its REMAP switch has no case for them). STATIC5 On 3.41.0, whether a layer read returns 82 or 156 records seems to follow what is stored (layers written before any second bank existed read 82) rather than the firmware alone. INFERRED The binding format itself was identical between 3.35.4 and 3.41.0 (82 records on each of three layers compared, 2026-09-21/22). MEASURED On 3.35.4 the LED map read before the upgrade and re-read after it differed; the nature of the change was not recorded.

3.28.7: no three-frame writes

On 3.28.7 never send a write that needs three frames; the half stops typing and answering until it is unplugged. Split writes into two-frame writes of whole records (see Transport).

The module battery command de/100b depends on the MODULE firmware, not the keyboard's:

Module firmware de/100b (millivolts) de/1009 (0.1 mV units)
2.1.2 absent: no data, about 1.09 s of timeout per request answers
2.2.2 absent: no reply answers
2.3.3 present answers

MEASURED (2.1.2 and 2.3.3 on the owner's boards) REPORTED (2.2.2, the nayactl maintainer)3 Details on Modules.

Stable across every version measured: the dock address map (3.28.7, 3.30.1, 3.41.0), the 136-entry LED map (3.28.7, 3.41.0), the frame format and the command ids. MEASURED REPORTED (3.30.1)1

Halves on different firmware

When the two halves run different keyboard firmware, the peripheral's port goes "hollow" (it completes the handshake and answers every command with an empty payload), its LEDs go dark, and typing still works on both halves. The halves report mutually correct pair addresses through a dead link, and NayaCore's pairing repair refuses with "Devices have different firmware versions". Matching the firmware restores everything; the central dropped off USB for about 2 s as the halves re-linked. Measured with a newer left half (3.41.0) and an older right half (3.35.4). The mismatched peripheral's version stays readable through the central's port at dst 51: the left port read the right half's version (3.35.4) while the right half's own port returned empty payloads. Relaying is partial: Bluetooth identity reads sent that way answer for the left half (see Transport). MEASURED 2026-09-20/2212 STATIC4 More on Split link.

Match the firmware first

Do not read or write a mismatched peripheral's port as if it were healthy: it answers empty payloads. Only newer-central with older-peripheral has been measured; flash the central (left) half first and then the right, and check fe/1002 on both afterwards.

What a firmware flash keeps

Across a keyboard firmware flash (3.35.4 to 3.41.0 and back, both halves), the Bluetooth bond tables stayed byte-identical, so pairing survives an update. After the upgrade both halves were very dim until the LED ceiling ed/1013 was re-sent with 100; whether the flash changed the stored ceiling or only the live level was not recorded. The keymap lives in the data partition and is not part of the firmware image. MEASURED 2026-09-201112 The flashing procedure itself (upload the whole resource, then reset; no separate mark step) is on Flashing.

If the board is dim after an update

Re-send the LED ceiling before anything else: ed/1013 params 00 00 64, whole frame aa 00 50 00 ed 05 10 13 00 00 64 67 04. This is a write of a persistent setting; it fixed a dim board on 2026-09-20/22. See LEDs.

Vendor change notes that touch the wire

Keyboard firmware, first version carrying each change (vendor release notes):

Version Changes
3.28.7 hold-tap keys sticking when two activated together, fixed
3.29.1 module update method prevents installing the wrong firmware
3.31.1 SystemCDC retired; LED PWM power control; LED colors out of sync between halves on boot and after sleep, fixed
3.35.4 BLE v2 (see Bluetooth); module battery management
3.39.4 (the note says 3.39.3) firmware-side LED remapping; LED notifications; power cycling on a low internal plus depleted module battery, fixed; reduced Bluetooth traffic between the halves
3.40.0 per-LED OFF
3.40.4 activity-timeout fixes; lower low-battery LED threshold; LED remap no longer overwrites LED actions; module update no longer needs the Solid effect
3.41.0 LED action override setting; colors offset onto the wrong keys during rapid updates, fixed; Tune phantom ticks on a layer switch, fixed

The stable 1.25.0 note merges the changes of 3.39.4 to 3.41.0 into one list under "v3.35.4 -> v3.41.0" and names no version in between. DOC798

Module firmware notes: 2.1.2 fixed the Track's Z-scroll being too easy; 2.2.0 added Force Module Update support and brightness sync for animations; 2.3.2 lowered the Tune's LED power by about 20 % and made tick counting exact; 2.3.3 fixed Tune phantom ticks near detents and disabled the battery blink. DOC79

NayaCore (host) changes that touch the wire: 5.8.1 made flashing up to 2.5x faster; 6.1.2 retired SystemCDC on the host side (a breaking Flow-to-Core message change); 6.1.4 fixed Interrupt Flavor and Tapping Term sometimes not being applied; 6.4.0 added BLE v2 support, the SPI flash test and format, and Clear BLE Devices; 6.9.2 redesigned device detection and fixed a pairing workflow that could fail silently; 6.10.2 handles a hold-tap flavor mismatch on write; 6.10.3 fixed modules not following the color map and a communication breakdown on a bit flip; 6.11.0 added Double Tap and Tap and Hold, the three LED setting commands, generation-B (_64) image updates, consolidated minimum versions, pairing error codes, a post-update BLE version check, ProtocolCDC command timeouts and a dongle crash fix. DOC79

Which versions are likely in use

Which firmware a reader runs is uncertain: 3.41.0 shipped weeks before the vendor stopped, a half can silently miss an update (one right half stayed on 3.35.4 while its left got 3.41.0), and the public installer download counts are highest for the releases carrying 3.29.1 and 3.35.4. Downloads are not flashes, and the Windows counts include auto-updates, so this is a weak reading. DOC109 INFERRED Check fe/1002 on both halves.

Safety

  • On 3.28.7 never send a write that needs three frames.
  • With halves on different firmware, do not treat the peripheral's port as healthy; match the firmware first, central first.
  • After an update, re-send ed/1013 100 before trying anything more drastic for a dim board.

Open questions

  • OPEN Every "not recorded" cell above, in particular nearly all behavior on 3.35.4, and anything on the beta-only 3.39.4, 3.40.0 and 3.40.4 (images archived in create-legacy-firmware; no board on them has been read); which versions besides 3.28.7 fail on three-frame writes (details).
  • OPEN Which firmware first lacks a USB serial number (tools fall back to side and product id) (details).
  • OPEN What changed in the LED data exchanged between the halves in 3.41 (details).
  • OPEN Why some 3.41.0 layers read 82 records and others 156 (details).

Sources


  1. nayactl, pull request #2 and its comments (a board on 3.30.1: text channel, dock addresses). ↩↩

  2. nayactl, pull request #5 and its comments (fe/1002 on 3.30.1; modules on 2.2.2). ↩↩↩

  3. nayactl, issue #4 (module battery readings by module firmware). ↩

  4. NayaFlow 1.25.1, NayaCore 6.11.0 strings (static reading): the pairing refusal. ↩

  5. NayaFlow 1.25.1, NayaCore 6.11.0 (Windows x64), our disassembly (2026-09-23): ProtocolCDCProcessWorker::_remapStartStep. ↩

  6. NayaFlow 1.25.1, NayaCore 6.11.0 (macOS arm64, cross-checked on x86_64), our disassembly (2026-09-23): the guarded initializers of the naya_fw::*_MinVersion values, operationMinFWVersion and commandMinFWVersion and their tables; see Disassembly. ↩↩

  7. create-legacy-firmware, vendor release notes, changelogs/ (NayaFlow 1.14.5 to 1.25.1). ↩↩↩↩↩

  8. create-legacy-firmware, firmware-history-beta/MANIFEST.json (commit 7b511ca: per beta release, the note's version, the app constant, NayaCore's literals and the carved images), with FIRMWARE-HISTORY.md. ↩↩↩

  9. Vendor release notes of the beta channel, NayaTech/NayaFlow-beta-releases (1.10.0 to 1.25.0). ↩↩↩↩↩↩

  10. Vendor release pages, NayaTech/NayaFlow-releases and the beta repository (download counts, snapshot 2026-08-28). ↩

  11. create-legacy-firmware, FLASHING-PROCEDURE.md, "Measured on hardware, both halves (2026-09-20)" (commit cdd897c; flow corrected in 6ef80e2: upload the whole resource, then reset, no mark step). ↩

  12. create-legacy-firmware, FLASHING-PROCEDURE.md, "Pairing and firmware mismatch" (commit cdd897c). ↩↩

  13. The naya-create-kb maintainer's published captures and dumps (a USB CDC capture log, keyboard 3.41.0); raw data decoded by us, never copied. ↩↩