Spaces:
Sleeping
Sleeping
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() |