0
mirror of https://github.com/bbenchoff/OrthoRoute.git synced 2026-08-23 14:37:00 +00:00
Files
OrthoRoute/.github/instructions/kicad-ipc.instructions.md

95 lines
3.5 KiB
Markdown

---
description: "Use when reading or writing KiCad IPC adapter code: pads, tracks, vias, zones, keepouts, layer names, coordinate units, protobuf fields. Covers rich_kicad_interface.py, ipc_adapter.py, and anything under infrastructure/kicad/."
applyTo: "orthoroute/infrastructure/kicad/**"
---
# KiCad IPC Adapter Conventions
These rules apply to all code under `orthoroute/infrastructure/kicad/`.
## Adapter Priority
Three adapters are tried in order — never skip the fallback chain:
1. **IPC API** (`ipc_adapter.py`) — KiCad 9.0+ socket/HTTP API. Preferred.
2. **SWIG** (`swig_adapter.py`) — Python bindings. Legacy fallback.
3. **File Parser** (`file_parser.py`) — Direct `.kicad_pcb` parsing. Always available.
Changes to one adapter must not break the others. Each implements the same interface from `application/interfaces/board_repository.py`.
## Coordinate Units
- KiCad IPC returns coordinates in **nanometres (nm)** as integers.
- All domain models use **millimetres (mm)** as floats.
- Convert at the adapter boundary — **never pass raw nm into domain objects**:
```python
# ✅ Correct
pad_x_mm = pad.position.x / 1_000_000 # nm → mm
# ❌ Wrong — nm leaks into domain
pad.position.x # raw nm value
```
## Layer Name Normalisation
IPC API returns layer names with a bus-prefix artifact. Strip it before storing:
```python
# IPC returns: "BL_F_Cu", "BL_In1_Cu", "BL_B_Cu"
# Domain needs: "F.Cu", "In1.Cu", "B.Cu"
layer_name = raw_name.removeprefix("BL_").replace("_", ".", 1)
```
Always normalize before passing layer names to domain models or the router.
## Protobuf Field Names
Key fields used in `rich_kicad_interface.py` — use these exact names, do not guess:
| Object | Proto field | Domain meaning |
|--------|-------------|----------------|
| Zone | `ZT_RULE_AREA` | Keepout / rule area (not copper fill) |
| Zone | `rule_area_settings` | Contains all five keepout constraint flags |
| Keepout flags | `keepout_tracks` | Blocks routing tracks |
| Keepout flags | `keepout_vias` | Blocks vias |
| Keepout flags | `keepout_copper` | Blocks copper fill (KiCad DRC only, router ignores) |
| Keepout flags | `keepout_pads` | Blocks pads |
| Keepout flags | `keepout_footprints` | Blocks footprints |
| Via | `drill_diameter` | Via drill size (nm) |
| Pad | `orientation` | Pad rotation in degrees |
## Keepout Extraction Pattern
Keepouts are extracted in `_extract_zones()` and returned as dicts — preserve this schema exactly:
```python
{
'name': str, # Zone name (may be empty string)
'layers': List[str], # Normalised layer names, e.g. ['In1.Cu', 'In2.Cu']
'outline': [[x, y], ...], # Polygon vertices in mm (already converted)
'keepout_tracks': bool,
'keepout_vias': bool,
'keepout_copper': bool, # Router does NOT enforce this flag
'keepout_pads': bool,
'keepout_footprints': bool,
}
```
## Router Enforcement Boundary
The router (`UnifiedPathFinder.initialize_graph`) enforces only `keepout_tracks` and `keepout_vias`.
`keepout_copper` is for KiCad DRC zone fills — do not add router enforcement for it.
## Error Handling
- IPC connection errors must be caught and trigger fallback to SWIG, not crash.
- Log failures at WARNING with the adapter name: `logger.warning("IPC adapter failed: %s", e)`.
- Never swallow errors silently in the fallback chain — always log before falling through.
## Tests
Mock the IPC socket at the adapter boundary; do not launch KiCad in unit tests.
Use `tests/infrastructure/kicad/` for adapter tests. See [docs/contributing.md](../../../docs/contributing.md).