Complete transformation pipeline for every key from hardware to GUI.
Pipeline Overview
HARDWARE ELECTRONICS DIGITAL RMK/VIAL
│ │ │ │
▼ ▼ ▼ ▼
Physical Key → (FiX,FoX) → (row,col) → (vrow,vcol)
name pins matrix virtual
5 Coordinate Systems:
| Stage | Name | Example | Description |
|---|
| 1 | Hardware | i1 | Physical key label (user perspective) |
| 2 | Electronics | (Fi4,Fo1) | Electrical matrix (input,output pins) |
| 3 | Digital | (3,0) | Firmware matrix scanner (row,col) |
| 4 | RMK | (3,0) | Virtual matrix for RMK keyboard engine |
| 5 | Vial | "3,0" | GUI display coordinates (same as RMK) |
Note: RMK and Vial share the same 12×6 virtual matrix coordinates.
Physical Layout Reference (User Perspective)
✋ LYNXcat (Left) LYNXcat (Right) 🤚
r1 m1 i1 t21 t11 t11 t21 i1 m1 r1
p1 r2 m2 i2 i5 t22 t12 t12 t22 i5 i2 m2 r2 p1
p4 p2 r3 m3 i3 i6 t33 t23 t13 t13 t23 t33 i6 i3 m3 r3 p2 p4
p5 p3 r4 m4 i4 i7 t24 t14 t14 t24 i7 i4 m4 r4 p3 p5
t25 t15 t15 t25
╰── FINGER (20) ─╯╰─ THUMB (11) ─╯ ╰─ THUMB (11) ─╯╰── FINGER (20) ─╯
Key Naming Convention:
i = index finger, m = middle, r = ring, p = pinky
t = thumb
- Numbers indicate row/position within finger group
i1-i4 = index column 1, i5-i7 = index column 2 (inner)
LEFT FINGER MODULE (20 Keys)
Electrical Wiring
╭─────╮╭─────╮╭─────╮
│ r1 ││ m1 ││ i1 │ Fi4 (GPIO35)
╰──┬──╯╰──┬──╯╰──┬──╯ Row 3
│ │ │
╭─────╮╭─────╮╭─────╮╭─────╮╭─────╮
│ p1 ││ r2 ││ m2 ││ i2 ││ i5 │ Fi3 (GPIO36)
╰──┬──╯╰──┬──╯╰──┬──╯╰──┬──╯╰──┬──╯ Row 2
│ │ │ │ │
╭─────╮╭─────╮╭─────╮╭─────╮╭─────╮╭─────╮
│ p4 ││ p2 ││ r3 ││ m3 ││ i3 ││ i6 │ Fi2 (GPIO37)
╰──┬──╯╰──┬──╯╰──┬──╯╰──┬──╯╰──┬──╯╰──┬──╯ Row 1
│ │ │ │ │ │
╭─────╮╭─────╮╭─────╮╭─────╮╭─────╮╭─────╮
│ p5 ││ p3 ││ r4 ││ m4 ││ i4 ││ i7 │ Fi1 (GPIO38)
╰──┬──╯╰──┬──╯╰──┬──╯╰──┬──╯╰──┬──╯╰──┬──╯ Row 0
│ │ │ │ │ │
Fo6 Fo5 Fo4 Fo3 Fo2 Fo1
(GPIO39)(GPIO40)(GPIO41)(GPIO42)(GPIO2)(GPIO1)
Col5 Col4 Col3 Col2 Col1 Col0
pinky pinky ring mid index index
outer inner inner outer
| Hardware | Electronics | Digital | RMK/Vial | Notes |
|---|
| Index Finger (Inner Column) | | | | |
| i7 | (Fi1, Fo1) | (0, 0) | (0, 0) | Bottom inner |
| i6 | (Fi2, Fo1) | (1, 0) | (1, 0) | |
| i5 | (Fi3, Fo1) | (2, 0) | (2, 0) | |
| - | - | (3, 0) | (3, 0) | Empty position |
| Index Finger (Outer Column) | | | | |
| i4 | (Fi1, Fo2) | (0, 1) | (0, 1) | Bottom outer |
| i3 | (Fi2, Fo2) | (1, 1) | (1, 1) | |
| i2 | (Fi3, Fo2) | (2, 1) | (2, 1) | |
| i1 | (Fi4, Fo2) | (3, 1) | (3, 1) | Top |
| Middle Finger | | | | |
| m4 | (Fi1, Fo3) | (0, 2) | (0, 2) | Bottom |
| m3 | (Fi2, Fo3) | (1, 2) | (1, 2) | |
| m2 | (Fi3, Fo3) | (2, 2) | (2, 2) | |
| m1 | (Fi4, Fo3) | (3, 2) | (3, 2) | Top |
| Ring Finger | | | | |
| r4 | (Fi1, Fo4) | (0, 3) | (0, 3) | Bottom |
| r3 | (Fi2, Fo4) | (1, 3) | (1, 3) | |
| r2 | (Fi3, Fo4) | (2, 3) | (2, 3) | |
| r1 | (Fi4, Fo4) | (3, 3) | (3, 3) | Top |
| Pinky (Inner Column) | | | | |
| p3 | (Fi1, Fo5) | (0, 4) | (0, 4) | Bottom inner |
| p2 | (Fi2, Fo5) | (1, 4) | (1, 4) | |
| p1 | (Fi3, Fo5) | (2, 4) | (2, 4) | Top |
| - | - | (3, 4) | (3, 4) | Empty position |
| Pinky (Outer Column) | | | | |
| p5 | (Fi1, Fo6) | (0, 5) | (0, 5) | Bottom outer |
| p4 | (Fi2, Fo6) | (1, 5) | (1, 5) | |
| - | - | (2, 5) | (2, 5) | Empty position |
| - | - | (3, 5) | (3, 5) | Empty position |
Visual Matrix (Firmware Perspective)
Col0 Col1 Col2 Col3 Col4 Col5
(Fo1) (Fo2) (Fo3) (Fo4) (Fo5) (Fo6)
───── ───── ───── ───── ───── ─────
Row 0 │ i7 i4 m4 r4 p3 p5 │ (Fi1) GPIO38 → Virt Row 0
Row 1 │ i6 i3 m3 r3 p2 p4 │ (Fi2) GPIO37 → Virt Row 1
Row 2 │ i5 i2 m2 r2 p1 -- │ (Fi3) GPIO36 → Virt Row 2
Row 3 │ -- i1 m1 r1 -- -- │ (Fi4) GPIO35 → Virt Row 3
LEFT THUMB MODULE (11 Keys)
Physical Layout (User View)
╭─────╮╭─────╮
│ t21 ││ t11 │ ← Thumb range top
╰─────╯╰─────╯
╭─────╮╭─────╮
│ t22 ││ t12 │
╰─────╯╰─────╯
╭─────╮╭─────╮╭─────╮
│ t33 ││ t23 ││ t13 │ ← Thumb range middle
╰─────╯╰─────╯╰─────╯
╭─────╮╭─────╮
│ t24 ││ t14 │
╰─────╯╰─────╯
╭─────╮╭─────╮
│ t25 ││ t15 │ ← Thumb range bottom
╰─────╯╰─────╯
inner column | outer column
Electrical Matrix (Firmware Scanner)
Note: Physical layout does NOT match electrical rows! The wiring pattern is non-obvious.
Col0 Col1 Col2
(To1) (To2) (To3)
───── ───── ─────
Row 0 │ t21 t33 t25 │ (Ti1) GPIO4
Row 1 │ t22 -- t24 │ (Ti2) GPIO5 ← Position (1,1) EMPTY
Row 2 │ t11 t23 t15 │ (Ti3) GPIO6
Row 3 │ t12 t13 t14 │ (Ti4) GPIO7
Key-to-Pin Wiring Reference
| Physical Position | Key | Electrical (Ti, To) | Digital (row, col) |
|---|
| Inner-left | t21 | (Ti1, To1) | (0, 0) |
| Inner-right | t11 | (Ti3, To1) | (2, 0) |
| 2nd row-left | t22 | (Ti2, To1) | (1, 0) |
| 2nd row-right | t12 | (Ti4, To1) | (3, 0) |
| Middle-left | t33 | (Ti1, To2) | (0, 1) |
| Middle-center | t23 | (Ti3, To2) | (2, 1) |
| Middle-right | t13 | (Ti4, To2) | (3, 1) |
| 4th row-left | t24 | (Ti2, To3) | (1, 2) |
| 4th row-right | t14 | (Ti4, To3) | (3, 2) |
| Outer-left | t25 | (Ti1, To3) | (0, 2) |
| Outer-right | t15 | (Ti3, To3) | (2, 2) |
| Hardware | Electronics | Digital | Virtual | Calculation | Notes |
|---|
| t21 | (Ti1, To1) | (0, 0) | (4, 0) | vrow=4+(0/2), vcol=(0%2)*3+0 | Top inner |
| t33 | (Ti1, To2) | (0, 1) | (4, 1) | vrow=4+(0/2), vcol=(0%2)*3+1 | |
| t25 | (Ti1, To3) | (0, 2) | (4, 2) | vrow=4+(0/2), vcol=(0%2)*3+2 | Bottom outer |
| t22 | (Ti2, To1) | (1, 0) | (4, 3) | vrow=4+(1/2), vcol=(1%2)*3+0 | |
| -- | -- | (1, 1) | (4, 4) | -- | EMPTY |
| t24 | (Ti2, To3) | (1, 2) | (4, 5) | vrow=4+(1/2), vcol=(1%2)*3+2 | |
| t11 | (Ti3, To1) | (2, 0) | (5, 0) | vrow=4+(2/2), vcol=(2%2)*3+0 | Top inner |
| t23 | (Ti3, To2) | (2, 1) | (5, 1) | vrow=4+(2/2), vcol=(2%2)*3+1 | |
| t15 | (Ti3, To3) | (2, 2) | (5, 2) | vrow=4+(2/2), vcol=(2%2)*3+2 | Bottom outer |
| t12 | (Ti4, To1) | (3, 0) | (5, 3) | vrow=4+(3/2), vcol=(3%2)*3+0 | |
| t13 | (Ti4, To2) | (3, 1) | (5, 4) | vrow=4+(3/2), vcol=(3%2)*3+1 | |
| t14 | (Ti4, To3) | (3, 2) | (5, 5) | vrow=4+(3/2), vcol=(3%2)*3+2 | Bottom |
Thumb Compaction Visualization
Physical 4×3 Matrix: Virtual 2×6 Matrix (Rows 4-5):
Col0 Col1 Col2 Col0 Col1 Col2 Col3 Col4 Col5
──── ──── ──── ──── ──── ──── ──── ──── ────
R0│ t21 t33 t25 │──────┐ R4│ t21 t33 t25 t22 -- t24 │
R1│ t22 -- t24 │──────┘ └─────────────────┴─────────────┘
R2│ t11 t23 t15 │──────┐ R5│ t11 t23 t15 t12 t13 t14 │
R3│ t12 t13 t14 │──────┘ └─────────────────┴─────────────┘
Formula: vrow = 4 + (phys_row / 2)
vcol = (phys_row % 2) * 3 + phys_col
RIGHT FINGER MODULE (20 Keys)
Electrical Wiring (Mirrored from Left)
╭─────╮╭─────╮╭─────╮
│ i1 ││ m1 ││ r1 │ Fi4 (GPIO35)
╰──┬──╯╰──┬──╯╰──┬──╯ Row 3
│ │ │
╭─────╮╭─────╮╭─────╮╭─────╮╭─────╮
│ i5 ││ i2 ││ m2 ││ r2 ││ p1 │ Fi3 (GPIO36)
╰──┬──╯╰──┬──╯╰──┬──╯╰──┬──╯╰──┬──╯ Row 2
│ │ │ │ │
╭─────╮╭─────╮╭─────╮╭─────╮╭─────╮╭─────╮
│ i6 ││ i3 ││ m3 ││ r3 ││ p2 ││ p4 │ Fi2 (GPIO37)
╰──┬──╯╰──┬──╯╰──┬──╯╰──┬──╯╰──┬──╯╰──┬──╯ Row 1
│ │ │ │ │ │
╭─────╮╭─────╮╭─────╮╭─────╮╭─────╮╭─────╮
│ i7 ││ i4 ││ m4 ││ r4 ││ p3 ││ p5 │ Fi1 (GPIO38)
╰──┬──╯╰──┬──╯╰──┬──╯╰──┬──╯╰──┬──╯╰──┬──╯ Row 0
│ │ │ │ │ │
Fo1 Fo2 Fo3 Fo4 Fo5 Fo6
(GPIO1)(GPIO2)(GPIO42)(GPIO41)(GPIO40)(GPIO39)
Col0 Col1 Col2 Col3 Col4 Col5
index index mid ring pinky pinky
outer inner inner outer
| Hardware | Electronics | Digital | RMK/Vial | Notes |
|---|
| Index Finger (Outer Column) | | | | |
| i7 | (Fi1, Fo1) | (0, 0) | (6, 0) | Bottom outer |
| i6 | (Fi2, Fo1) | (1, 0) | (7, 0) | |
| i5 | (Fi3, Fo1) | (2, 0) | (8, 0) | |
| - | - | (3, 0) | (9, 0) | Empty position |
| Index Finger (Inner Column) | | | | |
| i4 | (Fi1, Fo2) | (0, 1) | (6, 1) | Bottom inner |
| i3 | (Fi2, Fo2) | (1, 1) | (7, 1) | |
| i2 | (Fi3, Fo2) | (2, 1) | (8, 1) | |
| i1 | (Fi4, Fo2) | (3, 1) | (9, 1) | Top |
| Middle Finger | | | | |
| m4 | (Fi1, Fo3) | (0, 2) | (6, 2) | Bottom |
| m3 | (Fi2, Fo3) | (1, 2) | (7, 2) | |
| m2 | (Fi3, Fo3) | (2, 2) | (8, 2) | |
| m1 | (Fi4, Fo3) | (3, 2) | (9, 2) | Top |
| Ring Finger | | | | |
| r4 | (Fi1, Fo4) | (0, 3) | (6, 3) | Bottom |
| r3 | (Fi2, Fo4) | (1, 3) | (7, 3) | |
| r2 | (Fi3, Fo4) | (2, 3) | (8, 3) | |
| r1 | (Fi4, Fo4) | (3, 3) | (9, 3) | Top |
| Pinky (Inner Column) | | | | |
| p3 | (Fi1, Fo5) | (0, 4) | (6, 4) | Bottom inner |
| p2 | (Fi2, Fo5) | (1, 4) | (7, 4) | |
| p1 | (Fi3, Fo5) | (2, 4) | (8, 4) | Top |
| - | - | (3, 4) | (9, 4) | Empty position |
| Pinky (Outer Column) | | | | |
| p5 | (Fi1, Fo6) | (0, 5) | (6, 5) | Bottom outer |
| p4 | (Fi2, Fo6) | (1, 5) | (7, 5) | |
| - | - | (2, 5) | (8, 5) | Empty position |
| - | - | (3, 5) | (9, 5) | Empty position |
Visual Matrix (Firmware Perspective)
Col0 Col1 Col2 Col3 Col4 Col5
(Fo1) (Fo2) (Fo3) (Fo4) (Fo5) (Fo6)
───── ───── ───── ───── ───── ─────
Row 0 │ i7 i4 m4 r4 p3 p5 │ (Fi1) GPIO38 → Virt Row 6
Row 1 │ i6 i3 m3 r3 p2 p4 │ (Fi2) GPIO37 → Virt Row 7
Row 2 │ i5 i2 m2 r2 p1 -- │ (Fi3) GPIO36 → Virt Row 8
Row 3 │ -- i1 m1 r1 -- -- │ (Fi4) GPIO35 → Virt Row 9
RIGHT THUMB MODULE (11 Keys)
Physical Layout (User View - Mirrored from Left)
╭─────╮╭─────╮
│ t11 ││ t21 │ ← Thumb range top
╰─────╯╰─────╯
╭─────╮╭─────╮
│ t12 ││ t22 │
╰─────╯╰─────╯
╭─────╮╭─────╮╭─────╮
│ t13 ││ t23 ││ t33 │ ← Thumb range middle
╰─────╯╰─────╯╰─────╯
╭─────╮╭─────╮
│ t14 ││ t24 │
╰─────╯╰─────╯
╭─────╮╭─────╮
│ t15 ││ t25 │ ← Thumb range bottom
╰─────╯╰─────╯
outer column | inner column
Electrical Matrix (Same Mapping as Left)
Note: Physical layout is mirrored, but electrical matrix mapping is identical to left thumb.
Col0 Col1 Col2
(To1) (To2) (To3)
───── ───── ─────
Row 0 │ t21 t33 t25 │ (Ti1) GPIO4
Row 1 │ t22 -- t24 │ (Ti2) GPIO5 ← Position (1,1) EMPTY
Row 2 │ t11 t23 t15 │ (Ti3) GPIO6
Row 3 │ t12 t13 t14 │ (Ti4) GPIO7
Key-to-Pin Wiring Reference
| Physical Position | Key | Electrical (Ti, To) | Digital (row, col) |
|---|
| Inner-left | t11 | (Ti3, To1) | (2, 0) |
| Inner-right | t21 | (Ti1, To1) | (0, 0) |
| 2nd row-left | t12 | (Ti4, To1) | (3, 0) |
| 2nd row-right | t22 | (Ti2, To1) | (1, 0) |
| Middle-left | t13 | (Ti4, To2) | (3, 1) |
| Middle-center | t23 | (Ti3, To2) | (2, 1) |
| Middle-right | t33 | (Ti1, To2) | (0, 1) |
| 4th row-left | t14 | (Ti4, To3) | (3, 2) |
| 4th row-right | t24 | (Ti2, To3) | (1, 2) |
| Outer-left | t15 | (Ti3, To3) | (2, 2) |
| Outer-right | t25 | (Ti1, To3) | (0, 2) |
| Hardware | Electronics | Digital | Virtual | Calculation | Notes |
|---|
| t21 | (Ti1, To1) | (0, 0) | (10, 0) | vrow=10+(0/2), vcol=(0%2)*3+0 | Top inner |
| t33 | (Ti1, To2) | (0, 1) | (10, 1) | vrow=10+(0/2), vcol=(0%2)*3+1 | |
| t25 | (Ti1, To3) | (0, 2) | (10, 2) | vrow=10+(0/2), vcol=(0%2)*3+2 | Bottom outer |
| t22 | (Ti2, To1) | (1, 0) | (10, 3) | vrow=10+(1/2), vcol=(1%2)*3+0 | |
| -- | -- | (1, 1) | (10, 4) | -- | EMPTY |
| t24 | (Ti2, To3) | (1, 2) | (10, 5) | vrow=10+(1/2), vcol=(1%2)*3+2 | |
| t11 | (Ti3, To1) | (2, 0) | (11, 0) | vrow=10+(2/2), vcol=(2%2)*3+0 | Top inner |
| t23 | (Ti3, To2) | (2, 1) | (11, 1) | vrow=10+(2/2), vcol=(2%2)*3+1 | |
| t15 | (Ti3, To3) | (2, 2) | (11, 2) | vrow=10+(2/2), vcol=(2%2)*3+2 | Bottom outer |
| t12 | (Ti4, To1) | (3, 0) | (11, 3) | vrow=10+(3/2), vcol=(3%2)*3+0 | |
| t13 | (Ti4, To2) | (3, 1) | (11, 4) | vrow=10+(3/2), vcol=(3%2)*3+1 | |
| t14 | (Ti4, To3) | (3, 2) | (11, 5) | vrow=10+(3/2), vcol=(3%2)*3+2 | Bottom |
Thumb Compaction Visualization
Physical 4×3 Matrix: Virtual 2×6 Matrix (Rows 10-11):
Col0 Col1 Col2 Col0 Col1 Col2 Col3 Col4 Col5
──── ──── ──── ──── ──── ──── ──── ──── ────
R0│ t21 t33 t25 │──────┐ R10│ t21 t33 t25 t22 -- t24 │
R1│ t22 -- t24 │──────┘ └─────────────────┴─────────────┘
R2│ t11 t23 t15 │──────┐ R11│ t11 t23 t15 t12 t13 t14 │
R3│ t12 t13 t14 │──────┘ └─────────────────┴─────────────┘
Formula: vrow = 10 + (phys_row / 2)
vcol = (phys_row % 2) * 3 + phys_col
COMPLETE VIRTUAL MATRIX (12×6 = 72 Keys)
This is what RMK and Vial see:
Col0 Col1 Col2 Col3 Col4 Col5
───── ───── ───── ───── ───── ─────
Row 0 │ Li7 Li4 Lm4 Lr4 Lp3 Lp5 │ LeftCat Finger
Row 1 │ Li6 Li3 Lm3 Lr3 Lp2 Lp4 │
Row 2 │ Li5 Li2 Lm2 Lr2 Lp1 -- │
Row 3 │ -- Li1 Lm1 Lr1 -- -- │
═════════════════════════════════════════
Row 4 │ Lt21 Lt33 Lt25 Lt22 -- Lt24 │ LeftCat Thumb
Row 5 │ Lt11 Lt23 Lt15 Lt12 Lt13 Lt14 │
═════════════════════════════════════════
Row 6 │ Ri7 Ri4 Rm4 Rr4 Rp3 Rp5 │ RightCat Finger
Row 7 │ Ri6 Ri3 Rm3 Rr3 Rp2 Rp4 │
Row 8 │ Ri5 Ri2 Rm2 Rr2 Rp1 -- │
Row 9 │ -- Ri1 Rm1 Rr1 -- -- │
═════════════════════════════════════════
Row10 │ Rt21 Rt33 Rt25 Rt22 -- Rt24 │ RightCat Thumb
Row11 │ Rt11 Rt23 Rt15 Rt12 Rt13 Rt14 │
Empty Positions (4 per side = 8 total):
- Left Finger: (3,0), (3,4), (3,5), (2,5)
- Left Thumb: (4,4)
- Right Finger: (9,0), (9,4), (9,5), (8,5)
- Right Thumb: (10,4)
GPIO Pin Reference
Finger Module (Both Sides - Identical Wiring)
| Signal | GPIO | Direction | Function |
|---|
| Fi1 | GPIO38 | Input | Row 0 (bottom physical row) |
| Fi2 | GPIO37 | Input | Row 1 |
| Fi3 | GPIO36 | Input | Row 2 |
| Fi4 | GPIO35 | Input | Row 3 (top physical row) |
| Fo1 | GPIO1 | Output | Col 0 (index outer) |
| Fo2 | GPIO2 | Output | Col 1 (index inner) |
| Fo3 | GPIO42 | Output | Col 2 (middle) |
| Fo4 | GPIO41 | Output | Col 3 (ring) |
| Fo5 | GPIO40 | Output | Col 4 (pinky inner) |
| Fo6 | GPIO39 | Output | Col 5 (pinky outer) |
Thumb Module (Both Sides - Identical Wiring)
| Signal | GPIO | Direction | Function |
|---|
| Ti1 | GPIO4 | Input | Row 0 |
| Ti2 | GPIO5 | Input | Row 1 |
| Ti3 | GPIO6 | Input | Row 2 |
| Ti4 | GPIO7 | Input | Row 3 |
| To1 | GPIO18 | Output | Col 0 |
| To2 | GPIO8 | Output | Col 1 |
| To3 | GPIO3 | Output | Col 2 |
Source: firmware/common/src/key_index.rs
Finger Module (Direct Mapping)
// LeftCat Finger: physical = virtual (rows 0-3)
(DeviceRole::LeftCat, ModuleSlot::Finger) => (phys_row, phys_col)
// RightCat Finger: offset by 6 rows (rows 6-9)
(DeviceRole::RightCat, ModuleSlot::Finger) => (6 + phys_row, phys_col)
Thumb Module (4×3 → 2×6 Compaction)
// LeftCat Thumb: compact to rows 4-5
(DeviceRole::LeftCat, ModuleSlot::Thumb) => {
let virt_row = 4 + (phys_row / 2); // 0,1→4; 2,3→5
let virt_col = (phys_row % 2) * 3 + phys_col;
(virt_row, virt_col)
}
// RightCat Thumb: compact to rows 10-11
(DeviceRole::RightCat, ModuleSlot::Thumb) => {
let virt_row = 10 + (phys_row / 2); // 0,1→10; 2,3→11
let virt_col = (phys_row % 2) * 3 + phys_col;
(virt_row, virt_col)
}
Example: Tracing Key Li2 Through Pipeline
STAGE 1: HARDWARE
User presses key labeled "i2" on left finger module
Physical position: index finger, second row from top
STAGE 2: ELECTRONICS
Switch connects Fi3 (row input) to Fo2 (col output)
Signal path: GPIO36 (Fi3) ← switch → GPIO2 (Fo2)
STAGE 3: DIGITAL (Matrix Scanner)
MatrixDriver scans:
cols[1].set_low() // Fo2 = GPIO2
rows[2].is_low() == true // Fi3 = GPIO36 detects LOW
Result: (row=2, col=1)
STAGE 4: INPUT ACTION (Event Generation)
EventGenerator creates:
InputAction::KeyPress { row: 2, col: 1 }
FrameHeader adds routing:
sender: DeviceRole::LeftCat
module_slot: ModuleSlot::Finger
sequence_id: 42
STAGE 5: ESP-NOW (Wireless)
Frame serialized via postcard
Broadcast to tower (~0.5ms latency)
STAGE 6: VIRTUAL MATRIX (Tower)
physical_to_virtual(LeftCat, Finger, 2, 1):
→ Direct mapping for Finger
→ Virtual (2, 1)
STAGE 7: RMK/VIAL
RMK receives Event::KeyPress(row=2, col=1)
Keymap lookup: KEYMAP[layer][2][1] → KeyAction
Vial displays key at position "2,1" with label "Li2"
USB HID report generated → Host
Debugging Quick Reference
Wrong Key in Vial
| Symptom | Check | Fix |
|---|
| Wrong position | Firmware logs: verify KeyPress(row, col) | Hardware wiring issue |
| Wrong label | vial.json label at position | Update vial.json label |
| Key doesn't register | Sequence tracking logs | Check ESP-NOW reception |
Vial Position → Physical Key Lookup
Given Vial position (vrow, vcol):
IF vrow < 4: Left Finger
physical = (vrow, vcol)
key = see Left Finger table above
IF vrow 4-5: Left Thumb
phys_row = (vrow - 4) * 2 + (vcol >= 3 ? 1 : 0)
phys_col = vcol % 3
key = see Left Thumb table above
IF vrow 6-9: Right Finger
physical = (vrow - 6, vcol)
key = see Right Finger table above
IF vrow 10-11: Right Thumb
phys_row = (vrow - 10) * 2 + (vcol >= 3 ? 1 : 0)
phys_col = vcol % 3
key = see Right Thumb table above
Key Files
| File | Purpose |
|---|
firmware/common/src/key_index.rs | Transformation functions |
firmware/cat/src/config.rs | GPIO pin definitions |
firmware/tower/src/virtual_matrix.rs | RMK InputDevice bridge |
firmware/tower/vial.json | Vial layout definition |
firmware/tower/src/config.rs | Virtual matrix dimensions |