Commit graph

34 commits

Author SHA1 Message Date
Mae PUGIN
67a883dd0b feat: Add full flash (0x0) option to flasher offset combobox
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 21:20:03 +02:00
Mae PUGIN
1420bbcc74 fix: Flasher otadata erase timeout — skip flash_end between sequences
The ROM accepts consecutive flash_begin calls without an intervening
flash_end, so we no longer end+re-sync between the firmware write and
the otadata erase. Single flash_end after both sequences.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 18:38:29 +02:00
Mae PUGIN
3e54361d0d refactor: Modularize main.rs (2478 → 58 lines), flat architecture
Split monolithic main.rs into domain modules:
- context.rs: AppContext shared state, BgMsg enum, serial_spawn helper
- models.rs: UI model builders, keycap labels, key entries, layout preview
- config.rs: keyboard config export/import via binary protocol
- dispatch.rs: BgMsg handler + WPM/layout timers
- keymap.rs: key selection, layer switch/rename, heatmap toggle
- key_selector.rs: dispatch_keycode router, apply_keycode, hex/MT/LT
- macros.rs: macro CRUD, shortcut presets, step builder
- advanced.rs: combos, KO, leaders, tap dance, BT, tama, autoshift
- settings.rs: OTA flash, config backup, keyboard layout
- flasher.rs: ESP32 bootloader flash
- layout.rs: layout JSON preview, load/export
- connection.rs: serial connect/disconnect, tab auto-refresh
- stats.rs: stats refresh

Rename logic/ → protocol/ with cleaner file names.
Remove unused original-src/ directory.
Fix DarkLineEdit double styling, add rename popup, macro shortcuts.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 12:02:22 +02:00
Mae PUGIN
b5023b8f02 fix: Macro name off-by-one — M0 displayed as M1
decode_keycode used (raw >> 8) - 0x14 but macro codes start at 0x15,
so M0 (0x1500) decoded to index 1 instead of 0. Fixed to - 0x15.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-07 21:51:43 +02:00
Mae PUGIN
d1d10b7d73 feat: Binary protocol v2, config import/export, Tools tab, new layout format
- Migrate all serial commands from ASCII text to binary KS/KR frame protocol
  (SETLAYER, TD_LIST, COMBO_LIST, LEADER_LIST, KO_LIST, etc.)
- Add config import/export as JSON (keymaps, tap dances, combos, KO, leaders, macros)
- Merge Flash + Layout Preview into single Tools tab
- Replace WPF tree layout JSON format with flat groups+keys format:
  - Top-level "keys" for absolute positioning (thumbs, isolated keys)
  - "groups" with x/y/r transform, keys inside use local coordinates
  - Coordinates in units (1u = 50px), w/h default 1u, r default 0
- Layout auto-refresh (5s timer) for live preview while editing externally
- Pretty-print JSON in layout preview and export

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-07 21:30:04 +02:00
Mae PUGIN
88b51bd399 docs: Add README, LICENSE (GPL-3.0), prepare for public release
- README with features, build instructions, usage
- GPL-3.0 license (compatible with Slint GPLv3 tier)
- Updated Cargo.toml with license, description, repository
- Cleaned up .gitignore

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-07 16:50:39 +02:00
Mae PUGIN
efd1e8ebf4 fix: Remove macOS Intel target, fix CI
macOS x86_64 not needed (all modern Macs are ARM).
3 targets: Linux x86_64, Windows x86_64, macOS ARM64.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-07 16:39:52 +02:00
Mae PUGIN
476885576a fix: CI deps for Linux (fontconfig, xcb, xkbcommon, dbus, ssl)
Also fail-fast: false so other platforms still build.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-07 16:28:03 +02:00
Mae PUGIN
b06bf08cc3 release: v1.0.0 — KeSp Controller multi-platform
- Rename package to KeSp_controller
- Version 1.0.0
- GitHub Actions workflow for Linux/Windows/macOS releases
- Auto-build on tag push (v*)
- Window title and version strings updated

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-07 16:23:12 +02:00
Mae PUGIN
c42ed86d12 fix: Layer rename refreshes immediately
- Preserve active layer flag when rebuilding layer model after rename
- Add 100ms delay between rename command and layer names query
  (firmware needs time to save the new name)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-07 16:15:09 +02:00
Mae PUGIN
ddcb6c6e8f fix: Layer rename targets active layer + rename field width
- active-layer property now updated on switch_layer callback
  (rename was always targeting layer 0)
- Rename input constrained to 85px max-width (no overflow)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-07 16:10:00 +02:00
Mae PUGIN
d6e5a7f681 fix: OTA protocol with proper handshake
Previous OTA sent chunks blindly without waiting for firmware ACK.
Now properly implements the protocol:
1. Send "OTA <size>"
2. Wait for "OTA_READY" with 5s timeout
3. Send 4096-byte chunks, wait for "OTA_OK" after each
4. Stop on "OTA_DONE" or abort on "OTA_FAIL"
5. Proper port timeout management

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-07 15:41:21 +02:00
Mae PUGIN
0448efebc9 fix: Auto-erase otadata when flashing factory partition
When writing to factory (0x20000), automatically erase the otadata
partition (0xF000, 8KB) by writing 0xFF blocks. This forces the
bootloader to fall back to factory on next boot, instead of
continuing to boot from ota_0.

Without this, flashing factory "succeeds" but the ESP keeps
booting the old firmware from ota_0.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-07 15:16:57 +02:00
Mae PUGIN
195fa6e7e8 fix: Rewrite ESP32-S3 flasher to match esptool behavior
Root cause: missing SPI_SET_PARAMS (CMD 0x0B) before flash_begin.
ROM bootloader defaults to 2MB flash size, silently truncating
writes to 16MB flash. Progress bar showed success but firmware
was corrupt.

Changes:
- Add spi_set_params() with 16MB geometry before flash_begin
- Add MD5 verification after write (SPI_FLASH_MD5, CMD 0x13)
- Add retry logic (3 attempts per block)
- Pad firmware to 4-byte boundary
- flash_end(reboot=false) then separate hard reset after MD5 check
- Pure Rust MD5 implementation (no external crate)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-07 15:06:49 +02:00
Mae PUGIN
70fa72ddb7 feat: OTA firmware update via CDC serial (Settings tab)
OTA protocol (text-based, uses existing keyboard connection):
1. Send "OTA <size>"
2. Wait for firmware OTA_READY
3. Send firmware in 4096-byte chunks
4. Progress bar with chunk counter
5. OTA_DONE on completion

No programming cable needed - uses the same USB port as
keyboard communication. Browse for .bin file, click Flash OTA.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-07 13:45:12 +02:00
Mae PUGIN
2f53119178 fix: Heatmap gradient with stepped colors for clarity
mix() was not rendering correctly. Replaced with stepped thresholds:
- >80%: bright red (#ff0000)
- >60%: red-orange (#ff4400)
- >40%: orange (#ff8800)
- >20%: yellow (#ffcc00)
- >5%: cool blue (#446688)
- <=5%: very cold (#2d2d44)

Dark text when heat > 20%. Removed debug eprintln.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-07 13:35:08 +02:00
Mae PUGIN
af32862c76 fix: Heatmap readability - dark text on warm colors
- Gradient: dark purple -> orange -> red (more contrast than blue->yellow)
- Text switches to dark (#1a1a2e) when heat > 0.3
- Bold text in heatmap mode
- Sublabel opacity reduced in heatmap

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-07 13:23:12 +02:00
Mae PUGIN
61c3afc344 feat: Auto-refresh data on tab change
- Advanced tab: auto-loads TD, combos, leaders, KO, BT
- Macros tab: auto-loads macro list via binary protocol
- Stats tab: auto-loads heatmap + bigrams
- Only refreshes when connected
- 50ms delays between serial queries

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-07 13:16:26 +02:00
Mae PUGIN
b4ab9af18b fix: Macro list/save uses binary protocol (LIST_MACROS 0x30)
Firmware v2 doesn't respond to text "MACROS?" query.
Now uses binary LIST_MACROS (0x30) for refresh, with proper
parse_macros_binary() for the response payload.
Save still uses text MACROSEQ, then binary refresh after 100ms.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-07 12:34:40 +02:00
Mae PUGIN
0813e8531f fix: Auto-slot macros + heatmap auto-load on toggle
- Macro slot auto-assigned from macros.len() (no manual slot selection)
- Heatmap toggle auto-loads KEYSTATS? from firmware
- Debug logs for macro save/refresh

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-07 12:23:34 +02:00
Mae PUGIN
d69b421590 style: DarkLineEdit + scrollable layer sidebar
- DarkLineEdit: wrapper around std LineEdit with Dracula theme
  (dark bg, purple focus border)
- Replaced all remaining std LineEdit in: tab_keymap, tab_macros,
  tab_flasher, key_selector
- Layer sidebar: wrapped in Flickable for scrolling with many layers
- Zero std-widgets visual components remaining (except LineEdit
  inside DarkLineEdit wrapper)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-07 12:04:13 +02:00
Mae PUGIN
7b6f25a5ad fix: KO parser for actual firmware format
Firmware sends: "KO2: 0B+02->4C+00"
Parser expected: "KO0: trigger=2A mod=02 -> result=4C resmod=00"

Rewrote parse_ko_lines to match real format:
  <trigger_hex>+<mod_hex>-><result_hex>+<mod_hex>
Also skips "KO 0 deleted" and "KOSET 1:OK" lines.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-07 11:25:01 +02:00
Mae PUGIN
803505113b fix: Show modifiers in KO list (Shift+H -> Del)
KO list now displays modifier names alongside key names:
- "Shift+H" instead of just "H"
- Uses mod_name() to decode the bitmask

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-07 11:15:30 +02:00
Mae PUGIN
e8f4ee41a6 feat: KO creation with checkboxes (matching egui)
- Replace ModComboBox with Ctrl/Shift/Alt checkboxes for KO mods
- Build HID bitmask from checkboxes (Ctrl=0x01, Shift=0x02, Alt=0x04)
- Add DarkCheckbox component (Dracula theme)
- Descriptive label: "When you press [From] key, output [To] key instead"
- Read all KO fields from properties (no args in callback)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-07 11:06:32 +02:00
Mae PUGIN
33adcc5aa4 fix: Use correct index for combo/KO/leader creation
Index 255 does not mean "auto-assign" in the firmware.
Must use combo_data.len() as next index (matching egui behavior).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-07 10:58:07 +02:00
Mae PUGIN
ca21a6766d fix: Stop mixing binary and text serial protocols
Root cause of keyboard malfunction: binary SET/DELETE commands
followed by text QUERY commands confused the firmware state machine.

Changes:
- All create/delete (combo, leader, KO) back to TEXT protocol
  (matching stable egui desktop behavior)
- TD_SET kept binary (isolated, no text query after)
- 50ms delay between all consecutive serial commands
- Removed dead v2 check in refresh_advanced
- Added delay between KEYSTATS? and BIGRAMS? queries

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-07 10:50:18 +02:00
Mae PUGIN
a8f621e3d6 fix: Remove TAMA/AUTOSHIFT from Refresh All, add query delay
TAMA? and AUTOSHIFT? commands were causing keyboard to malfunction.
Added 50ms delay between serial queries to prevent buffer corruption.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-07 10:37:42 +02:00
Mae PUGIN
d3ee9ef16f fix: Switch all advanced commands to binary protocol v2
Combo, Leader, KO create/delete all use send_binary() now:
- COMBO_SET (0x60), COMBO_DELETE (0x62)
- LEADER_SET (0x70), LEADER_DELETE (0x72)
- KO_SET (0x91), KO_DELETE (0x93)

Text protocol commands (COMBOSET, COMBODEL, etc.) were not working
with the v2 firmware.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-07 09:26:52 +02:00
Mae PUGIN
362b0c729c fix: Combo key picker and TD buttons visibility
- Combo picker: pass key index directly instead of relying on selected_key_index
- TD actions: use DarkButton for consistent visibility
- Combo Add: validation message when keys not picked

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-07 09:20:54 +02:00
Mae PUGIN
4cfe2fbb7b feat: Editable Tap Dance + combo creation validation
Tap Dance:
- Each TD action is now a clickable button that opens the key selector
- Clicking an action -> pick key from popup -> sends TD_SET binary to firmware
- Labels show 1-tap / 2-tap / 3-tap / hold columns

Combo creation:
- Added validation: "Pick both keys first" message if keys not selected
- Debug log for COMBOSET command

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-07 09:09:41 +02:00
Mae PUGIN
d69d931ea9 style: Fix contrast on buttons, combobox, and tab titles
- button-bg lighter (#565970) to stand out from bg-secondary
- Border on DarkButton and DarkComboBox (#6272a4)
- Primary button: dark text on purple bg
- Tab titles: inactive #9a9ebb (was #6272a4), 13px, bold 700 when active

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-07 09:03:44 +02:00
Mae PUGIN
4e93f4fd97 style: Custom DarkComboBox + DarkTab (Dracula theme throughout)
- DarkComboBox: PopupWindow dropdown with Dracula colors, replaces all std ComboBox
- DarkTab: custom tab bar with purple underline, replaces std TabWidget
- All 7 .slint files updated, zero std-widgets Button/ComboBox/TabWidget remaining

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-07 08:46:39 +02:00
Mae PUGIN
28fbf10b79 style: Replace all std Button with custom DarkButton (Dracula theme)
Custom DarkButton component with Dracula theme colors:
- bg-secondary base, button-hover on hover
- primary variant with accent-purple
- Disabled state with reduced opacity
- Consistent 28px height, 4px border-radius

Also fixes PickDarkButton/KeyDarkButton naming errors from agent.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-06 20:52:44 +02:00
Mae PUGIN
32ee3a6d26 feat: Complete KeSp Controller — Slint UI port
Full port of the KaSe/KeSp split keyboard configurator from egui to Slint:
- 6 tabs: Keymap, Advanced, Macros, Stats, Settings, Flash
- Responsive keyboard view with scale-to-fit and key rotations
- Key selector popup with categorized grid, MT/LT builders, hex input
- Combo key picker with inline keyboard visual
- Macro step builder with visual tags
- Serial communication via background threads + mpsc polling
- Heatmap overlay with blue-yellow-red gradient
- OTA flasher with prog port VID filtering and partition selector
- WPM polling, Tamagotchi, Autoshift controls
- Dracula theme matching egui version

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-06 20:40:34 +02:00