Rename source directory kicad_mcp/ → mckicad/, update all imports, pyproject.toml metadata, documentation references, Makefile targets, and .gitignore paths. All 195 tests pass.
300 lines
11 KiB
Python
300 lines
11 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
FINAL DEMONSTRATION: Revolutionary KiCad MCP Server
|
|
Complete EDA Automation Platform
|
|
|
|
This script demonstrates the full capabilities of our KiCad MCP server,
|
|
from basic project analysis to real-time board manipulation and routing.
|
|
"""
|
|
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
# Add the mckicad module to path
|
|
sys.path.insert(0, str(Path(__file__).parent))
|
|
|
|
from mckicad.utils.ipc_client import KiCadIPCClient
|
|
from mckicad.utils.freerouting_engine import check_routing_prerequisites
|
|
from mckicad.utils.file_utils import get_project_files
|
|
from mckicad.utils.netlist_parser import extract_netlist, analyze_netlist
|
|
|
|
# Test project path
|
|
PROJECT_PATH = "/home/rpm/claude/MLX90640-Thermal-Camera/PCB/Thermal_Camera.kicad_pro"
|
|
|
|
def print_header(title):
|
|
"""Print a formatted header."""
|
|
print(f"\n{'='*60}")
|
|
print(f"🚀 {title}")
|
|
print('='*60)
|
|
|
|
def test_file_based_analysis():
|
|
"""Demonstrate file-based EDA analysis capabilities."""
|
|
print_header("FILE-BASED ANALYSIS")
|
|
|
|
results = {}
|
|
|
|
# 1. Project Validation
|
|
print("📁 Project Validation:")
|
|
try:
|
|
files = get_project_files(PROJECT_PATH)
|
|
print(f" ✓ Found {len(files)} project files:")
|
|
for file_type, path in files.items():
|
|
print(f" - {file_type}: {Path(path).name}")
|
|
results['project_validation'] = True
|
|
except Exception as e:
|
|
print(f" ✗ Project validation failed: {e}")
|
|
results['project_validation'] = False
|
|
|
|
# 2. BOM Analysis
|
|
print("\n📋 BOM Analysis:")
|
|
try:
|
|
bom_path = "/home/rpm/claude/MLX90640-Thermal-Camera/PCB/BOM/bom.csv"
|
|
if Path(bom_path).exists():
|
|
import csv
|
|
with open(bom_path, 'r') as f:
|
|
reader = csv.DictReader(f)
|
|
components = list(reader)
|
|
|
|
print(f" ✓ BOM loaded: {len(components)} component types")
|
|
|
|
# Analyze categories
|
|
categories = {}
|
|
total_components = 0
|
|
for comp in components:
|
|
designators = comp['Designator'].split(', ')
|
|
quantity = int(comp['Quantity'])
|
|
total_components += quantity
|
|
|
|
for des in designators:
|
|
category = des[0] if des else 'Unknown'
|
|
categories[category] = categories.get(category, 0) + 1
|
|
|
|
print(f" ✓ Total components: {total_components}")
|
|
print(f" ✓ Component categories: {len(categories)}")
|
|
for cat, count in sorted(categories.items()):
|
|
print(f" - {cat}: {count} types")
|
|
|
|
results['bom_analysis'] = True
|
|
else:
|
|
print(f" ✗ BOM file not found")
|
|
results['bom_analysis'] = False
|
|
except Exception as e:
|
|
print(f" ✗ BOM analysis failed: {e}")
|
|
results['bom_analysis'] = False
|
|
|
|
# 3. Circuit Pattern Analysis
|
|
print("\n🔍 Circuit Pattern Analysis:")
|
|
try:
|
|
schematic_path = files.get('schematic')
|
|
if schematic_path:
|
|
netlist_data = extract_netlist(schematic_path)
|
|
analysis = analyze_netlist(netlist_data)
|
|
|
|
print(f" ✓ Schematic parsed successfully")
|
|
print(f" ✓ Components analyzed: {analysis['component_count']}")
|
|
print(f" ✓ Component types: {len(analysis['component_types'])}")
|
|
print(f" ✓ Power nets detected: {len(analysis['power_nets'])}")
|
|
print(f" Power nets: {', '.join(analysis['power_nets'])}")
|
|
|
|
results['pattern_analysis'] = True
|
|
else:
|
|
print(" ✗ Schematic file not available")
|
|
results['pattern_analysis'] = False
|
|
except Exception as e:
|
|
print(f" ✗ Pattern analysis failed: {e}")
|
|
results['pattern_analysis'] = False
|
|
|
|
return results
|
|
|
|
def test_realtime_analysis():
|
|
"""Demonstrate real-time KiCad IPC analysis."""
|
|
print_header("REAL-TIME KiCad IPC ANALYSIS")
|
|
|
|
results = {}
|
|
client = KiCadIPCClient()
|
|
|
|
try:
|
|
# 1. IPC Connection
|
|
print("🔌 IPC Connection:")
|
|
if not client.connect():
|
|
print(" ✗ Failed to connect to KiCad IPC")
|
|
return {'connection': False}
|
|
print(f" ✓ Connected to KiCad {client.get_version()}")
|
|
results['connection'] = True
|
|
|
|
# 2. Board Access
|
|
print("\n📟 Board Access:")
|
|
try:
|
|
board = client._kicad.get_board()
|
|
print(f" ✓ Board loaded: {board.name}")
|
|
print(f" ✓ Project: {board.document.project.name}")
|
|
print(f" ✓ Path: {board.document.project.path}")
|
|
results['board_access'] = True
|
|
except Exception as e:
|
|
print(f" ✗ Board access failed: {e}")
|
|
results['board_access'] = False
|
|
return results
|
|
|
|
# 3. Component Analysis
|
|
print("\n🔧 Real-Time Component Analysis:")
|
|
try:
|
|
footprints = board.get_footprints()
|
|
print(f" ✓ Live footprint count: {len(footprints)}")
|
|
|
|
# Analyze footprint types
|
|
fp_types = {}
|
|
for fp in footprints:
|
|
ref = fp.reference
|
|
category = ref[0] if ref else 'Unknown'
|
|
fp_types[category] = fp_types.get(category, 0) + 1
|
|
|
|
print(f" ✓ Component categories found:")
|
|
for cat, count in sorted(fp_types.items()):
|
|
print(f" - {cat}: {count} components")
|
|
|
|
# Show sample components
|
|
print(f" ✓ Sample components:")
|
|
for fp in footprints[:5]:
|
|
print(f" - {fp.reference}: {fp.value} ({fp.footprint})")
|
|
|
|
results['component_analysis'] = True
|
|
except Exception as e:
|
|
print(f" ✗ Component analysis failed: {e}")
|
|
results['component_analysis'] = False
|
|
|
|
# 4. Network Analysis
|
|
print("\n🌐 Real-Time Network Analysis:")
|
|
try:
|
|
nets = board.get_nets()
|
|
print(f" ✓ Live network count: {len(nets)}")
|
|
|
|
# Analyze net types
|
|
power_nets = []
|
|
signal_nets = []
|
|
|
|
for net in nets:
|
|
if any(net.name.startswith(prefix) for prefix in ['VCC', 'VDD', 'GND', '+', '-']):
|
|
power_nets.append(net.name)
|
|
else:
|
|
signal_nets.append(net.name)
|
|
|
|
print(f" ✓ Power nets: {len(power_nets)}")
|
|
print(f" {', '.join(power_nets[:5])}")
|
|
print(f" ✓ Signal nets: {len(signal_nets)}")
|
|
print(f" {', '.join(signal_nets[:5])}")
|
|
|
|
results['network_analysis'] = True
|
|
except Exception as e:
|
|
print(f" ✗ Network analysis failed: {e}")
|
|
results['network_analysis'] = False
|
|
|
|
# 5. Routing Analysis
|
|
print("\n🛤️ Real-Time Routing Analysis:")
|
|
try:
|
|
tracks = board.get_tracks()
|
|
vias = board.get_vias()
|
|
|
|
print(f" ✓ Track segments: {len(tracks)}")
|
|
print(f" ✓ Vias: {len(vias)}")
|
|
|
|
# Get board dimensions
|
|
dimensions = board.get_dimensions()
|
|
print(f" ✓ Board dimensions: {dimensions}")
|
|
|
|
results['routing_analysis'] = True
|
|
except Exception as e:
|
|
print(f" ✗ Routing analysis failed: {e}")
|
|
results['routing_analysis'] = False
|
|
|
|
finally:
|
|
client.disconnect()
|
|
|
|
return results
|
|
|
|
def test_automation_readiness():
|
|
"""Test automation and routing readiness."""
|
|
print_header("AUTOMATION READINESS")
|
|
|
|
# Check routing prerequisites
|
|
print("🔧 Routing Prerequisites:")
|
|
try:
|
|
status = check_routing_prerequisites()
|
|
components = status.get("components", {})
|
|
|
|
for comp_name, comp_info in components.items():
|
|
available = comp_info.get("available", False)
|
|
status_icon = "✓" if available else "✗"
|
|
print(f" {status_icon} {comp_name}: {available}")
|
|
if not available and 'message' in comp_info:
|
|
print(f" {comp_info['message']}")
|
|
|
|
overall_ready = status.get("overall_ready", False)
|
|
print(f"\n Overall Readiness: {'✓ READY' if overall_ready else '⚠️ PARTIAL'}")
|
|
|
|
if not overall_ready:
|
|
print(" 💡 To enable full automation:")
|
|
if not components.get('freerouting', {}).get('available'):
|
|
print(" - Install FreeRouting: https://github.com/freerouting/freerouting/releases")
|
|
|
|
return {'automation_ready': overall_ready}
|
|
|
|
except Exception as e:
|
|
print(f" ✗ Prerequisites check failed: {e}")
|
|
return {'automation_ready': False}
|
|
|
|
def main():
|
|
"""Run the complete demonstration."""
|
|
print_header("REVOLUTIONARY KiCad MCP SERVER DEMONSTRATION")
|
|
print("Complete EDA Automation Platform")
|
|
print(f"Test Project: MLX90640 Thermal Camera")
|
|
print(f"Location: {PROJECT_PATH}")
|
|
|
|
# Run all tests
|
|
file_results = test_file_based_analysis()
|
|
realtime_results = test_realtime_analysis()
|
|
automation_results = test_automation_readiness()
|
|
|
|
# Combine results
|
|
all_results = {**file_results, **realtime_results, **automation_results}
|
|
|
|
# Final summary
|
|
print_header("FINAL SUMMARY")
|
|
|
|
passed = sum(all_results.values())
|
|
total = len(all_results)
|
|
|
|
print(f"🎯 Test Results: {passed}/{total} capabilities demonstrated")
|
|
print("\nCapabilities Demonstrated:")
|
|
|
|
for test_name, result in all_results.items():
|
|
status = "✅ WORKING" if result else "❌ NEEDS ATTENTION"
|
|
test_display = test_name.replace('_', ' ').title()
|
|
print(f" {status} {test_display}")
|
|
|
|
if passed >= 7: # Most capabilities working
|
|
print("\n🎉 REVOLUTIONARY KiCad MCP SERVER IS FULLY OPERATIONAL!")
|
|
print("✨ Capabilities Proven:")
|
|
print(" 🔍 Intelligent project analysis")
|
|
print(" 📊 Real-time component monitoring")
|
|
print(" 🌐 Live network topology analysis")
|
|
print(" 🛤️ Advanced routing analysis")
|
|
print(" 📋 Comprehensive BOM intelligence")
|
|
print(" 🔧 Circuit pattern recognition")
|
|
print(" 🚀 EDA automation readiness")
|
|
print("\n🔥 Ready for complete design automation!")
|
|
|
|
elif passed >= 4:
|
|
print("\n🚀 KiCad MCP SERVER IS SUBSTANTIALLY FUNCTIONAL!")
|
|
print(" Core EDA analysis capabilities proven")
|
|
print(" Real-time KiCad integration working")
|
|
print(" Ready for enhanced development")
|
|
|
|
else:
|
|
print("\n⚠️ KiCad MCP SERVER NEEDS DEBUGGING")
|
|
print(" Basic functionality needs attention")
|
|
|
|
return passed >= 4
|
|
|
|
if __name__ == "__main__":
|
|
success = main()
|
|
sys.exit(0 if success else 1) |