126 lines
No EOL
4.6 KiB
Python
126 lines
No EOL
4.6 KiB
Python
import wx
|
|
import serial
|
|
import threading
|
|
import time
|
|
|
|
class SerialMonitor(wx.Dialog):
|
|
def __init__(self, parent, port):
|
|
super().__init__(parent, title=f"Serial Monitor - {port}", size=(600, 400))
|
|
|
|
self.port = port
|
|
self.serial = None
|
|
self.running = False
|
|
self._destroyed = False
|
|
|
|
# Create UI elements
|
|
panel = wx.Panel(self)
|
|
vbox = wx.BoxSizer(wx.VERTICAL)
|
|
|
|
# Text area for output
|
|
self.text_area = wx.TextCtrl(panel, style=wx.TE_MULTILINE | wx.TE_READONLY | wx.HSCROLL)
|
|
vbox.Add(self.text_area, 1, wx.EXPAND | wx.ALL, 5)
|
|
|
|
# Input area
|
|
hbox = wx.BoxSizer(wx.HORIZONTAL)
|
|
self.input_field = wx.TextCtrl(panel, style=wx.TE_PROCESS_ENTER)
|
|
self.input_field.Bind(wx.EVT_TEXT_ENTER, self.on_send)
|
|
hbox.Add(self.input_field, 1, wx.EXPAND | wx.RIGHT, 5)
|
|
|
|
# Send button
|
|
send_button = wx.Button(panel, label="Send")
|
|
send_button.Bind(wx.EVT_BUTTON, self.on_send)
|
|
hbox.Add(send_button, 0)
|
|
|
|
vbox.Add(hbox, 0, wx.EXPAND | wx.ALL, 5)
|
|
|
|
# Baud rate selector
|
|
hbox2 = wx.BoxSizer(wx.HORIZONTAL)
|
|
hbox2.Add(wx.StaticText(panel, label="Baud Rate:"), 0, wx.ALIGN_CENTER_VERTICAL | wx.RIGHT, 5)
|
|
self.baud_selector = wx.Choice(panel, choices=["9600", "115200"])
|
|
self.baud_selector.SetSelection(1) # Default to 115200
|
|
self.baud_selector.Bind(wx.EVT_CHOICE, self.on_baud_change)
|
|
hbox2.Add(self.baud_selector, 0)
|
|
|
|
# Clear button
|
|
clear_button = wx.Button(panel, label="Clear")
|
|
clear_button.Bind(wx.EVT_BUTTON, self.on_clear)
|
|
hbox2.Add(clear_button, 0, wx.LEFT, 5)
|
|
|
|
vbox.Add(hbox2, 0, wx.EXPAND | wx.ALL, 5)
|
|
|
|
panel.SetSizer(vbox)
|
|
|
|
# Bind close event
|
|
self.Bind(wx.EVT_CLOSE, self.on_close)
|
|
|
|
self.start_monitor()
|
|
|
|
def start_monitor(self):
|
|
try:
|
|
baud = int(self.baud_selector.GetString(self.baud_selector.GetSelection()))
|
|
self.serial = serial.Serial(self.port, baud, timeout=0.1)
|
|
self.running = True
|
|
self.monitor_thread = threading.Thread(target=self.read_serial)
|
|
self.monitor_thread.daemon = True
|
|
self.monitor_thread.start()
|
|
except Exception as e:
|
|
wx.MessageBox(f"Error opening port: {str(e)}", "Error", wx.OK | wx.ICON_ERROR)
|
|
self.Close()
|
|
|
|
def read_serial(self):
|
|
while self.running:
|
|
if self.serial and self.serial.is_open:
|
|
try:
|
|
if self.serial.in_waiting:
|
|
data = self.serial.read(self.serial.in_waiting)
|
|
if data and not self._destroyed:
|
|
wx.CallAfter(self.append_text, data.decode('utf-8', errors='replace'))
|
|
except Exception as e:
|
|
if not self._destroyed:
|
|
wx.CallAfter(self.append_text, f"\nError reading from port: {str(e)}\n")
|
|
break
|
|
time.sleep(0.1)
|
|
|
|
def append_text(self, text):
|
|
if not self._destroyed and self and self.text_area:
|
|
try:
|
|
self.text_area.AppendText(text)
|
|
except:
|
|
pass # Ignore any errors if the window is being destroyed
|
|
|
|
def on_send(self, event):
|
|
if self.serial and self.serial.is_open and not self._destroyed:
|
|
text = self.input_field.GetValue() + '\n'
|
|
try:
|
|
self.serial.write(text.encode())
|
|
self.input_field.SetValue("")
|
|
except Exception as e:
|
|
if not self._destroyed:
|
|
wx.MessageBox(f"Error sending data: {str(e)}", "Error", wx.OK | wx.ICON_ERROR)
|
|
|
|
def on_baud_change(self, event):
|
|
if self.serial and not self._destroyed:
|
|
try:
|
|
self.serial.close()
|
|
self.start_monitor()
|
|
except Exception as e:
|
|
if not self._destroyed:
|
|
wx.MessageBox(f"Error changing baud rate: {str(e)}", "Error", wx.OK | wx.ICON_ERROR)
|
|
|
|
def on_clear(self, event):
|
|
if not self._destroyed and self.text_area:
|
|
self.text_area.SetValue("")
|
|
|
|
def on_close(self, event):
|
|
self.running = False
|
|
self._destroyed = True
|
|
if self.serial:
|
|
try:
|
|
self.serial.close()
|
|
except:
|
|
pass # Ignore any errors during cleanup
|
|
event.Skip()
|
|
|
|
def Destroy(self):
|
|
self._destroyed = True
|
|
super().Destroy() |