import threading import time import tkinter as tk from tkinter import messagebox, ttk import serial import serial.tools.list_ports class WaveformGenHMI: def __init__(self, root): self.root = root self.root.title("ESP32-P4 Waveform Generator") self.root.geometry("400x300") self.ser = None # UI Elements ttk.Label(root, text="Serial Port:").grid( row=0, column=0, padx=5, pady=5, sticky="w" ) self.port_var = tk.StringVar() self.port_combo = ttk.Combobox(root, textvariable=self.port_var) self.port_combo.grid(row=0, column=1, padx=5, pady=5) self.refresh_ports() ttk.Button(root, text="Connect", command=self.toggle_connect).grid( row=0, column=2, padx=5, pady=5 ) ttk.Label(root, text="GPIO Pin:").grid( row=1, column=0, padx=5, pady=5, sticky="w" ) self.pin_entry = ttk.Entry(root) self.pin_entry.insert(0, "21") self.pin_entry.grid(row=1, column=1, padx=5, pady=5) ttk.Label(root, text="Frequency (Hz):").grid( row=2, column=0, padx=5, pady=5, sticky="w" ) self.freq_slider = tk.Scale( root, from_=0, to=5000, orient=tk.HORIZONTAL, length=200 ) self.freq_slider.grid(row=2, column=1, columnspan=2, padx=5, pady=5) self.freq_entry = ttk.Entry(root, width=10) self.freq_entry.insert(0, "1000") self.freq_entry.grid(row=3, column=1, padx=5, pady=5, sticky="w") ttk.Button(root, text="Apply", command=self.send_config).grid( row=3, column=2, padx=5, pady=5 ) self.status_label = ttk.Label(root, text="Disconnected", foreground="red") self.status_label.grid(row=4, column=0, columnspan=3, pady=10) # Sync slider and entry self.freq_slider.bind("", lambda e: self.sync_entry_to_slider()) self.freq_entry.bind("", lambda e: self.sync_slider_to_entry()) def refresh_ports(self): ports = [p.device for p in serial.tools.list_ports.comports()] self.port_combo["values"] = ports if ports: self.port_combo.current(0) def sync_entry_to_slider(self): self.freq_entry.delete(0, tk.END) self.freq_entry.insert(0, str(self.freq_slider.get())) def sync_slider_to_entry(self): try: val = int(self.freq_entry.get()) if 0 <= val <= 5000: self.freq_slider.set(val) except ValueError: pass def toggle_connect(self): if self.ser and self.ser.is_open: self.ser.close() self.status_label.config(text="Disconnected", foreground="red") else: try: self.ser = serial.Serial(self.port_var.get(), 115200, timeout=1) self.status_label.config( text=f"Connected to {self.port_var.get()}", foreground="green" ) except Exception as e: messagebox.showerror("Error", f"Failed to connect: {e}") def send_config(self): if not self.ser or not self.ser.is_open: messagebox.showwarning("Warning", "Not connected to serial port") return try: pin = int(self.pin_entry.get()) freq = int(self.freq_entry.get()) if not (0 <= pin <= 54): raise ValueError("Pin must be 0-54") if not (0 <= freq <= 5000): raise ValueError("Frequency must be 0-5000") cmd = f"SET {pin} {freq}" self.ser.write(cmd.encode()) # Optional: read response line = self.ser.readline().decode().strip() if line: print(f"ESP32: {line}") except ValueError as e: messagebox.showerror("Error", str(e)) except Exception as e: messagebox.showerror("Error", f"Serial communication error: {e}") if __name__ == "__main__": root = tk.Tk() app = WaveformGenHMI(root) root.mainloop()