docs: expand CLAUDE.md with K17 Max, branch names, and EEPROM notes #19

Merged
rootiest merged 1 commits from chore/claude-docs into main 2026-04-13 17:02:12 +00:00
+40 -6
View File
@@ -1,13 +1,16 @@
# CLAUDE.md - QMK Development (Keychron Q5 Max)
# CLAUDE.md - QMK Development (Keychron Q5 Max / K17 Max)
Guidelines and commands for the customized Keychron Q5 Max firmware project based on the `wireless_playground` fork.
Guidelines and commands for the customized Keychron firmware project based on the `wireless_playground` fork.
## Project Scope
* **Origin:** [git.rootiest.dev/rootiest/qmk_firmware](https://git.rootiest.dev/rootiest/qmk_firmware)
* **Upstream:** [github.com/Keychron/qmk_firmware](https://github.com/Keychron/qmk_firmware) (branch: `wireless_playground`)
* **Primary Keyboard:** Keychron Q5 Max (ANSI Encoder)
* **Development Workflow:** Work is performed on the `q5_dev` branch before merging to `main`.
* **Secondary Keyboard:** Keychron K17 Max (occasionally)
* **Development Branches:**
* `dev/q5` — Q5 Max work-in-progress, merges to `main`
* `dev/k17` — K17 Max work-in-progress, merges to `main`
* **Feature Goals:** Tap-Dance, expanded layers, advanced Chording, Unicode support, and Auto-correct.
## Build and Flash Commands
@@ -28,6 +31,9 @@ Every `qmk` command below assumes the venv is active (or prefix each with
```bash
# Build the Q5 Max ANSI Encoder firmware
qmk compile -kb keychron/q5_max/ansi_encoder -km via
# Build the K17 Max firmware (rgb variant; separate 'white' LED variant exists)
qmk compile -kb keychron/k17_max/ansi_encoder/rgb -km via
```
### Flashing
@@ -35,6 +41,9 @@ qmk compile -kb keychron/q5_max/ansi_encoder -km via
```bash
# Flash the Q5 Max (requires the board to be in bootloader mode)
qmk flash -kb keychron/q5_max/ansi_encoder -km via
# Flash the K17 Max (requires the board to be in bootloader mode)
qmk flash -kb keychron/k17_max/ansi_encoder/rgb -km via
```
### Environment Setup
@@ -58,16 +67,41 @@ qmk config user.keymap=via
## Development Workflow
1. Verify the current branch is `q5_dev`.
2. Implement features in `keyboards/keychron/q5_max/ansi_encoder/keymaps/via/`.
1. Verify the current branch is `dev/q5` (Q5 Max) or `dev/k17` (K17 Max).
2. Implement features in the relevant keymap directory:
* Q5 Max: `keyboards/keychron/q5_max/ansi_encoder/keymaps/via/`
* K17 Max: `keyboards/keychron/k17_max/ansi_encoder/rgb/keymaps/via/`
3. Test compilation locally before committing.
4. Ensure `rules.mk` has the necessary flags enabled (e.g., `TAP_DANCE_ENABLE = yes`, `UNICODE_ENABLE = yes`).
## Git Conventions
* Use conventional commits (`feat:`, `fix:`, `docs:`, `chore:`, etc.) scoped to the keyboard where relevant (e.g. `feat(q5_max):`).
* Use conventional commits (`feat:`, `fix:`, `docs:`, `chore:`, etc.) scoped to the keyboard where relevant (e.g. `feat(q5_max):`, `fix(k17_max):`).
* Do **not** include `Co-Authored-By: Claude` trailers in commit messages.
### Chained / Stacked PRs
When merging a chain of PRs (e.g. `A → main`, `B → A`, `C → B`), always **delete the branch after each merge**. Gitea (and GitHub) will automatically retarget any open PRs pointing at the deleted branch to the branch it was merged into. This keeps the chain collapsing cleanly into `main` without manual retargeting or cleanup PRs.
## EEPROM Layout Notes
The Q5 Max uses wear-leveling EEPROM (STM32F401). Key layout facts:
* `EECONFIG_RGB_MATRIX` is at bytes 2431; byte 0 packs `mode[7:2] | enable[1:0]`.
* Keychron custom RGB data (effect list, regions, per-key colours, retail demo flag) lives in `EECONFIG_KB_DATABLOCK` immediately after `EECONFIG_BASE_SIZE` (37 bytes).
* `VIA_EEPROM_MAGIC_ADDR` is pinned to **544** in `ansi_encoder/config.h`. Do not lower this value — it must stay above `EECONFIG_BASE_SIZE + EECONFIG_KB_DATA_SIZE`. If Keychron EEPROM grows, raise 544 accordingly and clear EEPROM on the board.
* `EECONFIG_KB_DATA_SIZE` is computed in `eeconfig_kb.h` and requires an `#undef` before the `#define` to suppress QMK's default-zero value.
## Keychron RGB (`KEYCHRON_RGB_ENABLE`)
Enabled via `KEYCHRON_RGB_ENABLE = yes` in `rules.mk`. Key behavioural notes:
* `eeconfig_init_custom_rgb()` **loads** Keychron RGB state from EEPROM into RAM. It must be called in `keyboard_post_init_kb()` and in `wireless_enter_connected_kb()`; without it the arrays are zero-initialised and Launcher settings are lost on every boot or transport change.
* `eeconfig_reset_custom_rgb()` **writes** defaults to EEPROM and stamps the version. The version stamp (`eeprom_update_dword(EECONFIG_KEYBOARD, ...)`) belongs here only — not in the load path.
* `kc_rgb_save()` must call `eeconfig_update_rgb_matrix()` to persist the QMK RGB mode alongside the Keychron custom data; otherwise `rgb_matrix_init()` (triggered on every transport change by `REINIT_LED_DRIVER = 1`) reloads the compile-time default `RGB_MATRIX_TYPING_HEATMAP`.
* `retail_demo_enable` is a single byte. A bug in the original Keychron code used `eeprom_read_block` instead of `eeprom_update_block` in `eeconfig_reset_custom_rgb()`, leaving `0xFF` on freshly-flashed boards. `retail_demo_task()` treats any non-zero value as "demo active" and forces `CUSTOM_MIXED_RGB` every scan. The load path now clamps `> 1` to `0` and re-writes the byte as a one-time recovery.
* `default_per_key_led[]` and `default_region[]` must be defined in board-specific code (e.g. `ansi_encoder.c`) — `keychron_rgb.c` declares them `extern`.
## DIP Switch (Win/Mac)
The Win-side dip switch uses a **frame overlay** rather than calling `rgb_matrix_mode()`. A `dip_win_active` flag is set on switch change; `rgb_matrix_indicators_advanced_user()` paints all LEDs white each frame when the flag is set. This avoids writing to EEPROM and preserves the Launcher-configured effect, which would otherwise be overwritten by the direct mode call.