Files
qmk_firmware/CLAUDE.md
T
rootiest b4a76db6f3 docs: expand CLAUDE.md with K17 Max, branch names, and EEPROM notes
- Rename dev branch references from q5_dev to dev/q5; add dev/k17 for
  K17 Max work
- Add K17 Max build/flash commands using the correct rgb subvariant path
  (keychron/k17_max/ansi_encoder/rgb) to distinguish from the white LED
  variant
- Add EEPROM Layout Notes section documenting the Q5 Max address map,
  VIA_EEPROM_MAGIC_ADDR pinning rules, and EECONFIG_KB_DATA_SIZE #undef
  requirement
- Add Keychron RGB section capturing lessons from the persistence work:
  when to call eeconfig_init_custom_rgb(), version stamp placement,
  kc_rgb_save() mode persistence, retail_demo_enable 0xFF bug, and
  extern array requirements
- Add DIP Switch section explaining the frame overlay approach and why
  direct rgb_matrix_mode() calls must be avoided
2026-04-13 12:57:14 -04:00

108 lines
6.0 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# CLAUDE.md - QMK Development (Keychron Q5 Max / K17 Max)
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)
* **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
All commands must be run from the root of the repository **inside the project
Python virtual environment**. The system `qmk` is not used — activate the venv
first:
```bash
source .venv/bin/activate
```
Every `qmk` command below assumes the venv is active (or prefix each with
`source .venv/bin/activate &&`).
### Compilation
```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
```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
```bash
# Ensure the submodules are up to date (critical for the wireless_playground branch)
git submodule update --init --recursive
# Set the default keyboard/keymap
qmk setup
qmk config user.keyboard=keychron/q5_max/ansi_encoder
qmk config user.keymap=via
```
## Code Style and Patterns
* **Keymap Structure:** Keep the `keymap.c` organized by layers. Use descriptive defines for layer names (e.g., `_BASE`, `_FN`, `_CHORD`).
* **Feature Modules:** For advanced features like Chording or Tap-Dance, prefer creating separate headers/source files in the keymap folder to keep `keymap.c` readable.
* **Firmware Size:** Monitor the compiled `.bin` size, as wireless features and large feature sets (like Auto-correct) can quickly fill up flash memory.
* **Documentation:** Comment any complex chording logic or non-standard Tap-Dance implementations to ensure maintainability.
## Development Workflow
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):`, `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.