Skip to content

Latest commit

 

History

History
670 lines (499 loc) · 18 KB

File metadata and controls

670 lines (499 loc) · 18 KB

Schematic Wiring Implementation Plan

Date: 2026-01-10 Status: Planning Phase Priority: HIGH (User-requested feature for Issue #26)


Executive Summary

This plan outlines the implementation of complete schematic wiring functionality for the KiCAD MCP Server. Currently, component placement works perfectly with dynamic symbol loading, but wire/connection tools are incomplete or non-functional.

Goal: Enable users to create complete, functional schematics with wired connections between components through the MCP interface.


Current State Analysis

What Exists ✅

Files:

  • python/commands/connection_schematic.py - ConnectionManager class with wire/label methods
  • MCP handlers in kicad_interface.py for 6 connection-related tools

MCP Tools (Registered):

  1. add_schematic_wire - Add wire between two points
  2. add_schematic_connection - Connect two component pins
  3. add_schematic_net_label - Add net label
  4. connect_to_net - Connect pin to named net
  5. get_net_connections - Query net connections
  6. generate_netlist - Generate netlist from schematic

ConnectionManager Methods:

  • add_wire(schematic, start_point, end_point) - Add wire between coordinates
  • add_connection(schematic, source_ref, source_pin, target_ref, target_pin) - Connect pins
  • add_net_label(schematic, net_name, position) - Add label
  • connect_to_net(schematic, component_ref, pin_name, net_name) - Pin to net
  • get_pin_location(symbol, pin_name) - Get pin coordinates
  • get_net_connections(schematic, net_name) - Query connections
  • generate_netlist(schematic) - Generate netlist

What's Broken/Missing ❌

Problem 1: kicad-skip API Uncertainty

  • Code assumes schematic.wire.append() exists
  • Code assumes schematic.label.append() exists
  • Code assumes pins have .name and .location attributes
  • Need to verify what kicad-skip actually supports

Problem 2: Pin Location Calculation

  • Current implementation tries to calculate absolute pin positions
  • May not account for symbol rotation
  • May not work with multi-unit symbols
  • Pin numbering vs pin naming confusion

Problem 3: No Visual Feedback

  • No way to verify wires were created correctly
  • No validation of wire endpoints
  • No checks for overlapping wires or junctions

Problem 4: Limited Testing

  • No integration tests for wiring functionality
  • No validation with real KiCad schematics
  • User reported add_schematic_wire fails

Problem 5: Missing Features

  • No junction (wire intersection) support
  • No bus support (multi-bit signals)
  • No no-connect flags
  • No power symbols (VCC, GND graphical symbols)
  • No hierarchical labels

Technical Challenges

Challenge 1: kicad-skip Wire API

Issue: The kicad-skip library documentation is sparse. We need to determine:

  • Does schematic.wire exist?
  • What's the correct API to add wires?
  • How are wires stored in .kicad_sch files?

S-Expression Format (KiCad 8/9):

(wire (pts (xy 100 100) (xy 200 100))
  (stroke (width 0) (type default))
  (uuid "12345678-1234-1234-1234-123456789012")
)

Approach:

  1. Examine kicad-skip source code
  2. Test wire creation manually with kicad-skip
  3. Fall back to S-expression manipulation if necessary (similar to dynamic symbol loading)

Challenge 2: Pin Location Discovery

Issue: Need to find exact pin coordinates for automatic wiring.

Pin Data in Symbols: Pins are defined within symbol definitions in lib_symbols, with coordinates relative to symbol origin. When symbol is placed, pins move with it.

Required Information:

  • Symbol position (x, y)
  • Symbol rotation angle
  • Pin offset from symbol origin
  • Pin number/name mapping

Solution:

  1. Parse symbol definition to find pin definitions
  2. Apply transformation matrix (position + rotation) to pin coordinates
  3. Return absolute pin position in schematic space

Challenge 3: Smart Wire Routing

Issue: Users don't want to manually specify every wire segment.

Desired Behavior:

User: "Connect R1 pin 1 to C1 pin 1"
System:
  - Calculate R1 pin 1 location: (100, 100)
  - Calculate C1 pin 1 location: (150, 120)
  - Create wire path (orthogonal routing preferred):
    - (100, 100) → (100, 120) → (150, 120)
  - Or simple direct: (100, 100) → (150, 120)

Auto-Routing Options:

  1. Direct - Single wire segment (diagonal if needed)
  2. Orthogonal - Only horizontal/vertical segments (2 segments)
  3. Manhattan - Complex path avoiding components (3+ segments)

Phase 1 Approach: Start with direct wiring, add orthogonal later.

Challenge 4: Net Label Integration

Issue: Labels need to attach to wires, not float in space.

KiCad Behavior:

  • Labels must touch a wire or pin
  • Labels create electrical connections at their attachment point
  • Multiple labels with same name = connected net

Implementation:

  • When adding label, find nearest wire endpoint
  • Attach label to that coordinate
  • Or create short wire stub for label attachment

Implementation Phases

Phase 1: Core Wire Functionality (Week 1)

Goal: Get basic wiring working with kicad-skip API

Tasks:

  1. Research kicad-skip Wire API (4 hours)

    • Read kicad-skip source code
    • Test wire creation with Python REPL
    • Document actual API methods
    • Create test schematic with manual wires
  2. Fix Wire Creation (6 hours)

    • Update ConnectionManager.add_wire() with correct API
    • Handle S-expression manipulation if needed
    • Add UUID generation for wires
    • Test with simple wire (100,100) → (200,100)
  3. Implement Pin Discovery (8 hours)

    • Parse symbol definitions to extract pin data
    • Handle pin coordinates relative to symbol
    • Apply rotation transformation
    • Test with R, C, LED from dynamic symbols
  4. Fix add_schematic_connection (4 hours)

    • Use correct pin discovery
    • Create direct wire between pins
    • Handle error cases (pin not found, etc.)
    • Test with R1 pin 2 → C1 pin 1
  5. Integration Testing (4 hours)

    • Create test schematic with R, C, LED
    • Wire R to C
    • Wire C to LED
    • Verify schematic opens in KiCad
    • Verify electrical connectivity

Deliverables:

  • Working add_schematic_wire tool
  • Working add_schematic_connection tool
  • Pin location discovery working
  • Integration test passing
  • Documentation updated

Success Criteria:

  • User can connect two resistor pins with MCP command
  • Wire appears in KiCad schematic viewer
  • Netlist shows electrical connection

Phase 2: Net Labels & Named Nets (Week 1-2)

Goal: Enable named net connections (VCC, GND, etc.)

Tasks:

  1. Fix Net Label Creation (4 hours)

    • Update ConnectionManager.add_net_label()
    • Use correct kicad-skip API or S-expression
    • Position labels correctly
    • Test label creation
  2. Implement connect_to_net (6 hours)

    • Create wire stub from pin
    • Attach label to wire endpoint
    • Support common nets (VCC, GND, 3V3, etc.)
    • Test with multiple components on same net
  3. Net Connection Discovery (6 hours)

    • Parse wires and labels in schematic
    • Build connectivity graph
    • Implement get_net_connections()
    • Return all pins on a net
  4. Power Symbol Support (8 hours)

    • Add power symbols to templates (VCC, GND, 3V3, 5V)
    • Or dynamically load from power library
    • Connect power pins to power nets
    • Test complete circuit with power
  5. Testing (4 hours)

    • Create circuit with VCC, GND nets
    • Connect multiple components to each net
    • Verify net connectivity
    • Generate and validate netlist

Deliverables:

  • Working add_schematic_net_label tool
  • Working connect_to_net tool
  • Working get_net_connections tool
  • Power symbol support
  • Netlist generation working

Success Criteria:

  • User can label nets VCC, GND
  • Multiple components connect to same net
  • Netlist correctly shows net membership

Phase 3: Advanced Features (Week 2-3)

Goal: Professional schematic features

Tasks:

  1. Junction Support (4 hours)

    • Detect wire intersections
    • Add junction dots at T-junctions
    • S-expression: (junction (at x y) (diameter 0) (uuid ...))
  2. No-Connect Flags (2 hours)

    • Add "X" marks on unused pins
    • S-expression: (no_connect (at x y) (uuid ...))
  3. Orthogonal Routing (6 hours)

    • Implement 2-segment wire routing
    • Horizontal-then-vertical or vertical-then-horizontal
    • Choose best path based on pin positions
  4. Bus Support (8 hours)

    • Multi-bit signal buses
    • Bus labels (e.g., "D[0..7]")
    • Bus entries for individual signals
  5. Hierarchical Labels (8 hours)

    • Labels for hierarchical sheets
    • Input/Output/Bidirectional types
    • Sheet connections

Deliverables:

  • Junction creation
  • No-connect support
  • Smart orthogonal routing
  • Bus and hierarchical label support

Success Criteria:

  • Wires route cleanly around components
  • Junctions appear at wire intersections
  • Unused pins marked with no-connect

Phase 4: Validation & Polish (Week 3-4)

Goal: Production-ready reliability

Tasks:

  1. ERC Integration (6 hours)

    • Electrical Rule Check
    • Detect floating nets
    • Detect unconnected pins
    • Detect short circuits
  2. Visual Validation (4 hours)

    • Export schematic to PDF after wiring
    • Verify wire appearance
    • Check net label placement
  3. Comprehensive Testing (8 hours)

    • Test with Device library components
    • Test with IC components (multi-pin)
    • Test with connectors
    • Test complex circuits (10+ components)
  4. Error Handling (4 hours)

    • Graceful failures
    • Clear error messages
    • Validation of coordinates
    • Duplicate net label detection
  5. Documentation (6 hours)

    • Update MCP tool descriptions
    • Add usage examples to README
    • Create wiring tutorial
    • Add to CHANGELOG

Deliverables:

  • ERC validation
  • Comprehensive test suite
  • Error handling
  • Complete documentation

Success Criteria:

  • 95%+ test pass rate
  • Users can create functional circuits
  • Clear error messages on failures

Technical Approach

Option A: Use kicad-skip Native API (Preferred)

If kicad-skip supports wires natively:

# Add wire using native API
wire = schematic.wire.new(
    start=[100, 100],
    end=[200, 100]
)

# Add label
label = schematic.label.new(
    text="VCC",
    at=[150, 100]
)

Pros:

  • Clean, maintainable code
  • Follows library patterns
  • Less likely to break

Cons:

  • Depends on kicad-skip having these features
  • May be limited in functionality

Option B: S-Expression Manipulation (Fallback)

If kicad-skip doesn't support wires:

Use the same approach as dynamic symbol loading:

import sexpdata
from sexpdata import Symbol

# Read schematic
with open(schematic_path, 'r') as f:
    sch_data = sexpdata.loads(f.read())

# Create wire S-expression
wire_sexp = [
    Symbol('wire'),
    [Symbol('pts'),
        [Symbol('xy'), 100, 100],
        [Symbol('xy'), 200, 100]
    ],
    [Symbol('stroke'), [Symbol('width'), 0], [Symbol('type'), Symbol('default')]],
    [Symbol('uuid'), str(uuid.uuid4())]
]

# Insert into schematic
sch_data.append(wire_sexp)

# Write back
with open(schematic_path, 'w') as f:
    f.write(sexpdata.dumps(sch_data))

Pros:

  • Complete control
  • Can implement any feature
  • Works around library limitations

Cons:

  • More complex
  • Requires deep KiCad format knowledge
  • More maintenance

Hybrid Approach (Recommended)

  1. Try kicad-skip native API first
  2. Fall back to S-expression if needed
  3. Use S-expression for advanced features (junctions, buses)

Pin Discovery Algorithm

Step 1: Get Symbol Definition

Symbols are stored in lib_symbols section:

(lib_symbols
  (symbol "Device:R"
    (symbol "R_0_1"
      (rectangle (start -1 -2.54) (end 1 2.54) ...))
    (symbol "R_1_1"
      (pin passive line (at 0 3.81 270) (length 1.27)
        (name "~" (effects (font (size 1.27 1.27))))
        (number "1" (effects (font (size 1.27 1.27)))))
      (pin passive line (at 0 -3.81 90) (length 1.27)
        (name "~" (effects (font (size 1.27 1.27))))
        (number "2" (effects (font (size 1.27 1.27)))))))

Step 2: Extract Pin Information

For each pin:

  • Number (e.g., "1", "2")
  • Name (e.g., "GND", "VCC", "~" for unnamed)
  • Position relative to symbol origin: (at x y angle)
  • Length (distance from symbol body to connection point)

Step 3: Get Symbol Instance Position

From symbol instance in schematic:

(symbol (lib_id "Device:R") (at 100 100 0) (unit 1)
  (property "Reference" "R1" ...))

Extract:

  • Position: (at 100 100 0) = x=100, y=100, rotation=0°
  • Reference: "R1"

Step 4: Calculate Absolute Pin Position

def get_absolute_pin_position(symbol_instance, pin_definition):
    # Symbol position
    symbol_x, symbol_y, symbol_rotation = symbol_instance.at.value

    # Pin position relative to symbol
    pin_x, pin_y, pin_angle = pin_definition.at.value

    # Apply rotation transformation
    if symbol_rotation != 0:
        # Rotate pin coordinates around origin
        rad = math.radians(symbol_rotation)
        rotated_x = pin_x * math.cos(rad) - pin_y * math.sin(rad)
        rotated_y = pin_x * math.sin(rad) + pin_y * math.cos(rad)
        pin_x, pin_y = rotated_x, rotated_y

    # Translate to absolute position
    abs_x = symbol_x + pin_x
    abs_y = symbol_y + pin_y

    return [abs_x, abs_y]

Wire Routing Strategies

Strategy 1: Direct Wire (Phase 1)

Simplest: single wire segment from pin A to pin B.

R1 pin 2        C1 pin 1
   o-------------o

Pros: Simple, fast Cons: Diagonal wires (not standard practice)

Strategy 2: Orthogonal 2-Segment (Phase 3)

Two segments: horizontal then vertical, or vertical then horizontal.

R1 pin 2        C1 pin 1
   o-----┐
         │
         └------o

Algorithm:

  1. Calculate midpoint
  2. Route horizontal to midpoint
  3. Route vertical to target
  4. Or vice versa based on direction

Pros: Standard practice, cleaner schematics Cons: Slightly more complex

Strategy 3: Manhattan Routing (Future)

Complex multi-segment paths avoiding components.

Pros: Professional appearance Cons: Requires collision detection, path planning


Testing Strategy

Unit Tests

Test individual functions:

  • test_add_wire() - Wire creation
  • test_get_pin_location() - Pin discovery
  • test_add_net_label() - Label creation
  • test_calculate_pin_position() - Coordinate math

Integration Tests

Test complete workflows:

  • test_connect_two_resistors() - Wire R1 to R2
  • test_connect_to_vcc_net() - Multiple components to VCC
  • test_generate_netlist() - Netlist accuracy
  • test_schematic_opens_in_kicad() - File validity

Manual Validation

  • Create test schematic in KiCad manually
  • Add same connections via MCP
  • Compare results
  • Verify electrical connectivity in KiCad

Success Metrics

Phase 1 Success:

  • add_schematic_wire works (coordinates)
  • add_schematic_connection works (pin to pin)
  • Wires appear in KiCad schematic
  • Netlist shows connections
  • 3+ integration tests passing

Phase 2 Success:

  • Net labels work (VCC, GND, etc.)
  • Multiple components on same net
  • get_net_connections returns correct results
  • Netlist includes named nets
  • 5+ integration tests passing

Phase 3 Success:

  • Junctions at wire intersections
  • Orthogonal routing preferred
  • No-connect flags on unused pins
  • 10+ integration tests passing

Phase 4 Success:

  • ERC detects errors
  • 95%+ test coverage
  • Complete documentation
  • User can create functional circuits without errors

Risk Assessment

Risk Probability Impact Mitigation
kicad-skip lacks wire API High High Use S-expression fallback
Pin discovery complex Medium Medium Test with multiple symbol types
Rotation math errors Medium High Extensive testing, validation
Performance issues Low Medium Optimize S-expression parsing
KiCad format changes Low High Version detection, compatibility

Dependencies

Required:

  • kicad-skip >= 0.1.0 (or compatible)
  • sexpdata (already dependency for dynamic loading)
  • Python 3.8+

Optional:

  • KiCad CLI for validation (kicad-cli sch export netlist)

Timeline Estimate

Phase 1: 1 week (26 hours) Phase 2: 1 week (28 hours) Phase 3: 1.5 weeks (28 hours) Phase 4: 1.5 weeks (28 hours)

Total: 5 weeks (110 hours)

Accelerated path (core features only): 2-3 weeks (Phases 1-2)


Next Immediate Steps

  1. Research kicad-skip Wire API (TODAY)

    • Test with Python REPL
    • Document findings
    • Choose implementation approach
  2. Create Test Environment (TOMORROW)

    • Set up test schematic
    • Manual wire creation in KiCad
    • Export for comparison
  3. Implement Basic Wire (THIS WEEK)

    • Update ConnectionManager.add_wire()
    • Test with simple coordinates
    • Verify in KiCad
  4. Fix Pin Discovery (THIS WEEK)

    • Parse symbol definitions
    • Calculate absolute positions
    • Test with rotated symbols

User Communication

For Issue #26:

Update users that:

  • ✅ Component placement is DONE (with 10,000+ symbols)
  • ⏳ Wire/connection tools are IN PROGRESS
  • 📅 Estimated completion: 2-3 weeks for core functionality
  • 🎯 Goal: Complete functional schematics with wiring

Status: Ready for implementation Owner: TBD Priority: HIGH (user-blocking feature)