qmk_userspace/qmk_flash_tools/README.md
2025-10-09 14:45:23 +02:00

338 lines
8.8 KiB
Markdown

# QMK Flash Tools - Modular Edition
Automated flashing tools for QMK split keyboards with RP2040 controllers (like Liatris).
## 📁 Structure
```
qmk_flash_tools/
├── autoflash_modular.sh # Main flashing script
├── lib/ # Reusable library modules
│ ├── device_detection.sh # USB device detection functions
│ ├── side_mapping.sh # Device-to-side mapping storage
│ └── qmk_helpers.sh # QMK build/flash wrappers
├── test/ # Standalone test scripts
│ ├── test_device_detection.sh
│ ├── test_side_mapping.sh
│ └── test_qmk_helpers.sh
└── README.md # This file
```
## 🚀 Quick Start
### 1. Flash Both Sides
```bash
cd qmk_flash_tools
chmod +x autoflash_modular.sh
./autoflash_modular.sh
```
The script will:
1. Build firmware once
2. **First time only:** Ask which side you'll flash (left/right)
3. **Subsequent runs:** Auto-detect which side is plugged in
4. Wait for you to enter bootloader
5. Verify and flash with correct handedness
6. Repeat for the other side
### 2. Test Individual Components
```bash
# Test device detection
cd test
chmod +x test_device_detection.sh
./test_device_detection.sh
# Test side mapping
chmod +x test_side_mapping.sh
./test_side_mapping.sh
# Test QMK helpers
chmod +x test_qmk_helpers.sh
./test_qmk_helpers.sh
```
## 🔧 Configuration
Edit the top of `autoflash_modular.sh`:
```bash
KEYBOARD="fingerpunch/sweeeeep" # Your keyboard
KEYMAP="smathev" # Your keymap
USB_MOUNT_PATHS=(...) # Where USB drives mount
SIDE_MAPPING_FILE="..." # Device mappings (defaults to ./device_mappings.json)
```
## 📚 Library Documentation
### device_detection.sh
Functions for detecting RP2040 devices via host USB information.
**Key Functions:**
- `wait_for_rp2040()` - Wait for device to enter bootloader
- `get_usb_serial_from_host(mount_point)` - Get USB serial from host
- `get_usb_device_path(mount_point)` - Get USB port location
- `get_device_identifier(mount_point)` - Get best available ID
- `print_device_info(mount_point)` - Debug info
**Example:**
```bash
source lib/device_detection.sh
mount_point=$(wait_for_rp2040)
device_id=$(get_device_identifier "$mount_point")
echo "Device: $device_id"
```
### side_mapping.sh
Functions for storing and retrieving which device is left/right.
**Key Functions:**
- `init_mapping_file()` - Create mapping file if needed
- `save_side_mapping(device_id, side)` - Save mapping
- `get_saved_side(device_id)` - Retrieve saved side
- `detect_side(device_id)` - Get side (prompts if unknown)
- `list_all_mappings()` - Show all saved mappings
- `clear_mapping(device_id)` - Remove a mapping
- `clear_all_mappings()` - Reset all mappings
**Example:**
```bash
source lib/side_mapping.sh
export SIDE_MAPPING_FILE="./device_mappings.json"
save_side_mapping "serial:ABC123" "left"
side=$(get_saved_side "serial:ABC123")
echo "Side: $side"
```
### qmk_helpers.sh
Wrapper functions for QMK CLI commands.
**Key Functions:**
- `check_qmk_installed()` - Verify QMK is available
- `build_firmware(keyboard, keymap)` - Compile firmware
- `flash_side(keyboard, keymap, side)` - Flash with handedness
- `flash_with_bootloader(keyboard, keymap, bootloader)` - Flash with specific bootloader
- `verify_keyboard_exists(keyboard)` - Check keyboard definition
- `clean_build()` - Clean build artifacts
**Example:**
```bash
source lib/qmk_helpers.sh
check_qmk_installed || exit 1
build_firmware "fingerpunch/sweeeeep" "smathev"
flash_side "fingerpunch/sweeeeep" "smathev" "left"
```
## 🧪 Testing Workflow
### Test Device Detection
1. **Without device:**
```bash
./test/test_device_detection.sh
# Shows "no device found", good for baseline
```
2. **With device:**
```bash
# Enter bootloader mode on keyboard
./test/test_device_detection.sh
# Shows USB serial, path, and identifier
```
### Test Side Mapping
```bash
./test/test_side_mapping.sh
# Runs comprehensive tests:
# - Create mapping file
# - Save/retrieve mappings
# - Clear mappings
# - Interactive prompt (optional)
```
### Test QMK Helpers
```bash
./test/test_qmk_helpers.sh
# Tests:
# - QMK installation check
# - Keyboard verification
# - Build (optional)
# - Function signatures
```
## 🐛 Troubleshooting
### Device not detected
```bash
# Check if device appears
ls /media/$USER/
# Should see RPI-RP2 or similar
# Run device detection test
./test/test_device_detection.sh
```
### Can't identify device
The script uses these methods in order:
1. USB serial number (most reliable)
2. USB physical port path
3. Mount point name (fallback)
Check which method worked:
```bash
source lib/device_detection.sh
mount_point="/media/$USER/RPI-RP2"
print_device_info "$mount_point"
```
### Side mismatch detected
If you see a mismatch warning:
**Option 1: Exit and plug in correct side (safest)**
- Choose `[e]` to exit
- Unplug the keyboard
- Plug in the correct side
- Run the script again
**Option 2: Update the mapping**
- Choose `[c]` to clear old mapping and save new one
- Use this if you know the old mapping was wrong
**Option 3: Force flash (dangerous!)**
- Choose `[f]` to flash anyway
- Only use if you're absolutely certain
- May result in swapped left/right behavior
Or manually reset mappings:
```bash
source lib/side_mapping.sh
clear_mapping "serial:ABC123" # Use your device ID
```
Or reset all mappings:
```bash
cd qmk_flash_tools
rm device_mappings.json
```
### Build fails
```bash
# Test QMK directly
qmk compile -kb fingerpunch/sweeeeep -km smathev
# Check keyboard exists
qmk list-keymaps -kb fingerpunch/sweeeeep
```
## 💡 Advanced Usage
### Use in other scripts
```bash
#!/usr/bin/env bash
source /path/to/qmk_flash_tools/lib/device_detection.sh
source /path/to/qmk_flash_tools/lib/side_mapping.sh
# Your custom logic here
mount_point=$(wait_for_rp2040)
device_id=$(get_device_identifier "$mount_point")
side=$(detect_side "$device_id")
echo "Detected $side side"
```
### Custom keyboard configuration
```bash
# Set environment variables before running
export KEYBOARD="your/keyboard"
export KEYMAP="your_keymap"
./autoflash_modular.sh
```
### Different mapping file
```bash
export SIDE_MAPPING_FILE="/tmp/my_test_mappings.json"
./autoflash_modular.sh
```
## 📋 Requirements
- **bash** - Shell interpreter
- **qmk** - QMK CLI (`python3 -m pip install qmk`)
- **jq** - JSON processor (`sudo apt-get install jq`)
- **findmnt** - Usually included with util-linux
- **udevadm** - Usually included with systemd
## 🔒 File Permissions
Make scripts executable:
```bash
chmod +x autoflash_modular.sh
chmod +x test/*.sh
chmod +x lib/*.sh
```
## 📝 How Device Mapping Works
The script intelligently handles three states:
### 🟢 Empty Mapping (First Time)
- **No devices mapped yet**
- **Asks:** "Which side will you flash first?"
- Script learns both sides as you flash them
- First device = saved as what you specify (left/right)
- Second device = saved as the other side
- Result: Complete mapping of both sides
### 🟡 Partial Mapping (One Side Known)
- **One device mapped, one unknown**
- **Auto-detects:** No asking needed!
- If you plug in the known device → "Detected: left side"
- If you plug in unknown device → "Detected: right side (inferred)"
- Result: Completes mapping automatically
### 🔴 Complete Mapping (Both Sides Known)
- **Both devices are mapped**
- **Auto-detects:** Fully automatic!
- Plug in any side → "Detected: left side" or "Detected: right side"
- Only the two known devices are allowed
- Unknown device → **Rejected immediately** (safety feature)
- Result: Fast, automatic flashing with full protection
### Why This Matters
- **First run**: Asks which side (one-time setup) ✅
- **Normal use**: Fully automatic - just plug and flash! ✅
- **Protection**: Unknown devices rejected - can't flash wrong keyboard ✅
- **Smart**: Knows when to ask vs. when to auto-detect 🧠
## 📝 Additional Notes
- **Input timing**: You're asked which side BEFORE entering bootloader (so you can still type!)
- **EEPROM wipe**: Liatris overwrites EEPROM on flash, so we use HOST USB info
- **Board-ID**: INFO_UF2.TXT is NOT unique per device, don't rely on it
- **USB serial**: Burned into RP2040 chip, persists even when EEPROM wiped
## 🆘 Support
Issues? Check:
1. Run test scripts to isolate the problem
2. Check device detection with `print_device_info()`
3. Verify mappings with `list_all_mappings()`
4. Test QMK commands directly: `qmk compile -kb ... -km ...`
## 📄 License
Same as your QMK userspace configuration.