I’m working on a Python application that acts as a bridge between a serial port and a UDP socket. The app has a GUI built with Tkinter and uses threads to handle reading from the serial port and forwarding data over UDP, as well as listening for UDP packets and writing them back to the serial port.
teh app has a start bridge function which ends with creating the threads as seen below:
self.stop_event.clear()
self.read_thread = threading.Thread(target=self.read_and_send_serial_data, daemon=True)
self.read_thread.start()
self.listen_thread = threading.Thread(target=self.listen_and_forward_udp_data, daemon=True)
self.listen_thread.start()
here are the thread functions:
def read_and_send_serial_data(self):
self.log("Serial->UDP thread started")
udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
while not self.stop_event.is_set():
try:
if self.serial_conn.in_waiting > 0:
data = self.serial_conn.read(self.serial_conn.in_waiting)
udp_socket.sendto(data, (self.target_ip, int(self.target_port)))
self.log(f"Sent: {data}")
except Exception as e:
self.log(f"Error: {e}")
time.sleep(self.interval)
udp_socket.close()
def listen_and_forward_udp_data(self):
self.log("UDP->Serial thread started")
listen_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
listen_socket.bind(('', int(self.listen_port)))
listen_socket.setblocking(False) # Set socket to non-blocking mode
while not self.stop_event.is_set():
try:
ready_to_read, _, _ = select.select([listen_socket], [], [], 1.0)
if ready_to_read:
data, addr = listen_socket.recvfrom(1024) # Buffer size 1024 bytes
if data:
self.serial_conn.write(data)
self.log(f"Received from {addr}: {data}")
else:
time.sleep(0.1)
except socket.error as e:
self.log(f"Error: {e}")
break
listen_socket.close()
self.log("Listening thread terminated")
When I try to stop the bridge, I run into issues with the join method not returning in the listen_thread
.
my stop_bridge function:
def stop_bridge(self):
self.stop_event.set()
if self.read_thread.is_alive():
self.log("Stopping Reading Serial Thread")
self.read_thread.join()
self.log("Thread joined.")
if self.listen_thread.is_alive():
self.log("Stopping Listening UDP Thread")
self.log("Waiting for the thread to join.")
self.listen_thread.join() # Add a timeout to join
self.log("Thread joined.")
if self.serial_conn:
self.serial_conn.close()
self.log("Bridge stopped.")
self.start_button.config(state=tk.NORMAL)
self.stop_button.config(state=tk.DISABLED)
self.status_label.config(text="Status: Not running")
The issue I’m facing is that the listen_thread does not return from the join call. The only way to get it to sort of work is to add a timeout to join, but that means the thread might still be running…
Both threads open sockets and close them inside their respective functions, and I’ve made sure the stop_event is set to stop the loop.
Has anyone faced a similar issue or can suggest a better approach? Is there a better threading library I should consider, or am I missing something with the current implementation?
Thanks in advance for any help!