File size: 4,850 Bytes
a715790
 
 
 
0fae916
 
6cb9bde
 
 
 
 
0fae916
 
 
 
 
 
 
 
 
 
4d0cfc5
 
 
 
 
 
 
 
 
 
 
 
 
9b3f017
4d0cfc5
7ebeb3b
8e9c148
 
 
e2a4d50
7ebeb3b
b26efca
 
 
 
 
 
6cb9bde
7ebeb3b
 
 
 
 
 
 
0fae916
f6f763c
0fae916
 
 
 
 
 
 
a715790
 
0fae916
 
 
 
9b3f017
0fae916
a715790
4d0cfc5
 
 
6cb9bde
0fae916
 
 
 
 
a715790
 
 
0fae916
a715790
 
 
 
0fae916
 
a715790
 
 
 
 
5db575c
a715790
0fae916
 
a715790
0fae916
a715790
0fae916
 
 
 
 
a715790
 
 
6cb9bde
 
 
9b3f017
6cb9bde
 
0fae916
9b3f017
0fae916
 
 
 
9b3f017
 
 
 
0fae916
 
 
 
 
 
 
a715790
5db575c
0fae916
a715790
0fae916
 
 
 
 
 
a715790
 
0fae916
a715790
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
import gradio as gr
from skidl import *
import tempfile
import os
import time
import sys
import logging

# Set up logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

# Check for required dependencies
try:
    import gradio
    import skidl
except ImportError as e:
    print(f"Missing dependency: {e}")
    print("Please install requirements: pip install gradio skidl")
    sys.exit(1)

def check_device_lib():
    """Check if device.lib exists in the current directory."""
    current_dir = os.getcwd()
    device_lib_path = os.path.join(current_dir, 'device.lib')
    if os.path.exists(device_lib_path):
        logger.info(f"Found device.lib in current directory: {device_lib_path}")
        return True
    logger.warning(f"device.lib not found in current directory: {current_dir}")
    return False

def configure_skidl_libs():
    """Configure SKiDL to use device.lib from the current directory."""
    current_dir = os.getcwd()
    # Clear existing library search paths
    lib_search_paths.clear()
    
    # Assume lib_search_paths is a dict (newer SKiDL)
    lib_key = getattr(skidl, 'LIB_SPICE', 'spice')
    lib_search_paths[lib_key] = [current_dir]
    logger.info(f"Using dict-based lib_search_paths with key '{lib_key}' and {current_dir}")

    # Conditionally set default library if set_default_lib exists
    try:
        set_default_lib('Device')
        logger.info("Set default library to Device using set_default_lib")
    except NameError:
        logger.info("set_default_lib not available; relying on lib_search_paths for Device library")

    # Suppress KiCad warnings by setting dummy environment variables
    os.environ['KICAD_SYMBOL_DIR'] = current_dir
    os.environ['KICAD6_SYMBOL_DIR'] = current_dir
    os.environ['KICAD7_SYMBOL_DIR'] = current_dir
    os.environ['KICAD8_SYMBOL_DIR'] = current_dir
    logger.info("Set dummy KiCad environment variables to suppress warnings")

def cleanup_old_files():
    """Clean up temporary files older than 1 hour."""
    temp_dir = tempfile.gettempdir()
    for f in os.listdir(temp_dir):
        if f.endswith('.net') and os.path.getmtime(os.path.join(temp_dir, f)) < time.time() - 3600:
            try:
                os.remove(os.path.join(temp_dir, f))
            except OSError:
                pass

def generate_circuit(skidl_code):
    """Generate circuit netlist from SKiDL code."""
    if not skidl_code.strip():
        return "Error: Empty code provided", None

    reset()
    tmp_path = None
    try:
        configure_skidl_libs()
        if not check_device_lib():
            return "Error: device.lib not found in the current directory. Please ensure it exists.", None

        try:
            compile(skidl_code, '<string>', 'exec')
        except SyntaxError as e:
            return f"Syntax Error: {e}", None

        with tempfile.NamedTemporaryFile(delete=False, suffix='.py') as tmp:
            tmp.write(skidl_code.encode('utf-8'))
            tmp_path = tmp.name

        namespace = {}
        exec(open(tmp_path).read(), namespace)

        netlist_str = generate_netlist()
        if not netlist_str.strip():
            return "Error: No netlist generated", None

        with tempfile.NamedTemporaryFile(delete=False, suffix='.net', mode='w') as out_file:
            out_file.write(netlist_str)
            netlist_file_path = out_file.name

        return "Netlist generated successfully!", netlist_file_path

    except SyntaxError as e:
        return f"Syntax Error: {e}", None
    except Exception as e:
        return f"Error: {str(e)}", None
    finally:
        if tmp_path and os.path.exists(tmp_path):
            try:
                os.remove(tmp_path)
            except OSError:
                pass

# Gradio UI
with gr.Blocks() as demo:
    gr.Markdown(
        """
        # SKiDL Circuit Builder (No KiCad Needed)
        **Note**: Ensure `device.lib` is in the same directory as this script to resolve components like resistors, LEDs, etc.
        """
    )
    
    # Example code: 5 LEDs with resistors
    example_code = """
from skidl import *
vcc = Vcc()
gnd = Gnd()
leds = [Part('Device', 'LED', value='LED') for _ in range(5)]
resistors = [Part('Device', 'R', value='220') for _ in range(5)]
for r, led in zip(resistors, leds):
    vcc & r & led & gnd
"""
    
    skidl_input = gr.Textbox(
        label="Enter SKiDL Code Here",
        lines=20,
        placeholder=example_code
    )
    output_message = gr.Textbox(label="Status / Error", interactive=False)
    download_btn = gr.File(label="Download Netlist (.net)")
    
    run_button = gr.Button("Build Circuit")
    
    run_button.click(
        fn=generate_circuit,
        inputs=[skidl_input],
        outputs=[output_message, download_btn]
    )

if __name__ == "__main__":
    cleanup_old_files()
    demo.launch()