1
votes

I am trying to create a python interface to send frames to arduino and receive can frames from arduino and display it . for the sending data it works fine , but for the receiving I was little bit confused how to handle it. I tried to create a thread that will be started once the serial com is establashed. I have 2 questions : 1/ Is it the right way to create thread ? 2/ how to stop the thread from running once I disconnect the serial connection here's my GUI with an example of receiving random value from arduino

from tkinter import* 
from tkinter import  filedialog, Label, Entry, LabelFrame, Button, Tk
from tkinter import ttk
from db_class import up
import serial_tx_rx
from tkinter import messagebox
from diagservices import diag_services
import threading
import serial
import tkinter.scrolledtext as tkscrolledtext

class MainWindow():
    def __init__(self, master):
        self.master = master
        self.title = self.master.title("CanSim")
        self.size = self.master.geometry('950x200')
        self.baudrate = 9600
        self.com_port = ['COM1', 'COM2', 'COM3', 'COM4', 'COM5', 'COM6', 'COM7', 'COM8', 'COM9', 'COM10']
        self.isopen = False
        self.receivedMessage = None
        self.stop_thread = False
        self.bConnect = ttk.Button(self.master, text="Connect", command = self.connectSerial)
        self.bConnect.place(x=750, y=7)
        self.bDisconnect = ttk.Button(self.master, text="Disconnect", command= self.disconnectSerial)
        self.bDisconnect.place(x=750, y=30)
        self.com_portCmb = ttk.Combobox(self.master, width=8, values =self.com_port )
        self.com_portCmb.place(x=830, y=7)
        self.Frame = Frame(self.master, bg= 'cyan')
        self.Frame.place(x=10, y=30)
        self.comStatusLabel = Label(master, text= "Disconnected ", font=("Helvetica", 8, "normal", "italic"))
        self.comStatusLabel.place(x=830, y=33)
        self.textbox = tkscrolledtext.ScrolledText(self.Frame, wrap='word',font=2, width=55, height=8) 
        self.textbox.pack(side='bottom', fill='y', expand=True, padx=0, pady=0)
        self.textbox.config(font="bold")
        self.textbox.yview_pickplace("end")

    def connectSerial(self):
        try:
            self.ser = serial.Serial(self.com_portCmb.get(), self.baudrate)
            self.comStatusLabel["text"] = "Connected"
            self.isopen =True
            self.t1 = threading.Thread(target=self.readSerial)
            self.t1.start()
        except:
            messagebox.showerror("Error : Invalid COM ", "Fail to establish connection with the selected COM Port" )

    def disconnectSerial(self):
        self.t1.daemon()
        self.ser.close()
        self.comStatusLabel["text"] = "Disconnected"

    def readSerial(self):
        if self.isopen:
            self.received_data = self.ser.read(2)
            self.textbox.insert(END, str(self.received_data)+"\n")
            print(self.received_data)
            self.textbox.after(100, self.readSerial)

if __name__ == "__main__":
    root = Tk()
    ex = MainWindow(root)
    root.mainloop()
1

1 Answers

0
votes

You should not use .after() in a threaded task (readSerial()), use while loop instead:

class MainWindow():
    def __init__(self, master):
        self.master = master
        self.title = self.master.title("CanSim")
        self.size = self.master.geometry('950x200')
        self.ser = None
        ...

    def disconnectSerial(self):
        if self.ser and self.ser.is_open:
            #self.t1.daemon()  # daemon is an attribute, not function
            self.ser.close()
            self.comStatusLabel["text"] = "Disconnected"

    def readSerial(self):
        while self.ser.is_open:
            self.received_data = self.ser.read(2)
            self.textbox.insert(END, str(self.received_data)+"\n")
            print(self.received_data)