0

I am trying to create a simple GUI application using tkinter that runs three test scripts when a button is pressed. I've decided to use the threading module because I noticed that the GUI halts execution when it tries to execute any of these test scripts (each is a separate .py file). Each of this script utilizes the python CAN module that has an instance in the beginning allowing the script to a PCAN device

When I run the tests individually each of the script runs concurrently with the TKinter.py application and the GUI does not freeze, but when I select all the scripts to run together, each of the scripts ends up starting a different thread and this causes an issue because my PCAN device can only be initialized for one script at a time and if I run multiple together at similar times, the results would end up being inaccurate.

I want to find out if there is a way to let the tkinter app run its course with no affect while the test cases are running but the test cases only run in sequence one after another.

Please note if I use the join method from threading, the GUI still stops responding because of it. Please help.

# Library Imports
from tkinter import *
import os
import threading
from CAN_Test1 import Test1
from CAN_Test2 import Test2
from CAN_Test3 import Test3
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
from matplotlib.figure import Figure




## Dimensions of Window
root = Tk()
root.title("Acceptance Testing: UDS ISO-14229")
root.geometry("830x445")



# Plot Figure in Canvas's
f1 = Figure(figsize=(3,3), dpi=100)
axes_1 = f1.add_axes([0.2,0.15,0.7,0.7])
axes_1.set_title("Ignition Status")
axes_1.set_ylim(-1,8)
# axes_1.set_xlabel("Time")
axes_1.set_yticks(ticks=[0,1,3,4,6], labels=["OFF", "START", "ACC", "RUN", "CRANK"])
axes_1.set_xticks(ticks=[])

f2 = Figure(figsize=(3,3), dpi=100)
axes_2 = f2.add_axes([0.2,0.15,0.7,0.7])
axes_2.set_title("Vehicle Speed")
axes_2.set_ylim(-5,100)
# axes_2.set_xlabel("Time")
axes_2.set_ylabel("Speed in Kph")
axes_2.set_xticks(ticks=[])



# Canvas's for matplotlib figures
canvas3 = FigureCanvasTkAgg(f1,root)
canvas3.draw()
canvas3.get_tk_widget().grid(row=1, column=2, rowspan=10, columnspan=6, padx=10, pady=10)

canvas4 = FigureCanvasTkAgg(f2,root)
canvas4.draw()
canvas4.get_tk_widget().grid(row=1, column=8, rowspan=10, columnspan=6, padx=10, pady=10)



# Functions for test execution and opening logs, report and trace window:
def test1_runstat():
    global option1
    option1 = var1.get()

def test2_runstat():
    global option2
    option2 = var2.get()

def test3_runstat():
    global option3
    option3 = var3.get()

def test_run():
    # count=0
    # test_list=[Test1, Test2, Test3]
    test_list_status=[]
    test_list_status.append(option1)
    test_list_status.append(option2)
    test_list_status.append(option3)

    # for item in test_list_status:
    #     if item == "ON":
    #         t1 = threading.Thread(target=test_list[count])
    #         t1.start()
    #         count += 1
    #         if count == 3:
    #             return


    if test_list_status[0] == "ON":
        t1 = threading.Thread(target=Test1)
        t1.start()
    if test_list_status[1] == "ON":
        t1 = threading.Thread(target=Test2)
        t1.start()
    if test_list_status[2] == "ON":
        t1 = threading.Thread(target=Test3)
        t1.start()
    else:
        pass



def open_trace_window():
    os.startfile("C:\\Program Files\\PEAK-System\\PEAK-Drivers 4\\Tools\\PcanView.exe")


def open_log_file_dir():
    os.startfile("C:\\Users\\15202\\OneDrive\\Desktop\\L2P\\Python\\CAN_Logs")



# Declaring variables for checking receive a result (if the button is pressed or not)
var1 = StringVar()
var2 = StringVar()
var3 = StringVar()




# A) Assigning three check boxes for three tests; B) Assigning four buttons: Start Test/Tests,Open Logs,Generate Report
# and Open Pcan Viewer
# A)
myLabel1 = Label(root, text="Test Scenarios:")
e1 = Entry(root, width=30)
e1.grid(row=11,column=6)
e1.insert(0,"Enter Ign State: 0/1/3/4/6")
e2 = Entry(root, width=30)
e2.grid(row=11,column=13)
e2.insert(0,"Enter Veh Spd")
chk_btn1 = Checkbutton(root, text="Test Scenario 1", variable=var1, onvalue="ON", offvalue="OFF", command=test1_runstat)
chk_btn2 = Checkbutton(root, text="Test Scenario 2", variable=var2, onvalue="ON", offvalue="OFF", command=test2_runstat)
chk_btn3 = Checkbutton(root, text="Test Scenario 3", variable=var3, onvalue="ON", offvalue="OFF", command=test3_runstat)
# B)
btn1 = Button(root, text="Start Test/Tests", command=test_run)
btn2 = Button(root, text="Logs & Reports", command=open_log_file_dir)
btn3 = Button(root, text="Generate Report")
btn4 = Button(root, text="Open Trace Window", command=open_trace_window)
# C) Empty Space
myLabel4 = Label(root, text="").grid(row=12,column=0)
myLabel5 = Label(root, text="").grid(row=13,column=0)




# A) Place buttons on gui using grid; B) deselect them all initially; C) set option values to "OFF" the first time
# A)
myLabel1.grid(row=0, column=0)
chk_btn1.grid(row=1, column=0, pady=5)
chk_btn2.grid(row=2, column=0, pady=5)
chk_btn3.grid(row=3, column=0, pady=5)
chk_btn1.anchor(W)
chk_btn2.anchor(W)
chk_btn3.anchor(W)
btn1.grid(row=14, column=0, padx=5)
btn2.grid(row=14, column=1, padx=5)
btn3.grid(row=14, column=2, padx=5)
btn4.grid(row=14, column=13)

# B)
chk_btn1.deselect()
chk_btn2.deselect()
chk_btn3.deselect()

# C)
option1 = "OFF"
option2 = "OFF"
option3 = "OFF"




# The Runner !!!
root.mainloop()

'''


One Test Script of 3
'''

'''

1) Set up the H/W for the test
2) Create a Vehicle Simulation by defining some RBS messages and Tx them at their respective periodicity
3) Run the actual test for DTC
4) Stop the simulation

'''

# # Import the needed modules
import can
import time

def Test1():

    # 1)
    bus = can.interface.Bus(bustype='pcan', channel='PCAN_USBBUS1', baudrate=500000)

    # 2)
    ## Define the messages to transmit periodically and as a single transmit:
    msg_3B3 = can.message.Message(arbitration_id=0x3B3, data=[0x40,0x84,0xC0,0x0C,0x00,0x00,0x00,0x00], extended_id=False)
    msg_41E = can.message.Message(arbitration_id=0x41E, data=[0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF], extended_id=False)
    msg_44C = can.message.Message(arbitration_id=0x44C, data=[0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF], extended_id=False)
    msg_59E = can.message.Message(arbitration_id=0x59E, data=[0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF], extended_id=False)

    msg_740_10_01 = can.message.Message(arbitration_id=0x740, data=[0x02,0x10,0x01,0x00,0x00,0x00,0x00,0x00], extended_id=False)
    msg_740_10_03 = can.message.Message(arbitration_id=0x740, data=[0x02,0x10,0x01,0x00,0x00,0x00,0x00,0x00], extended_id=False)




    ## Periodicty for messages per dbc file:
    periodicity_msg_3B3 = 0.5
    periodicity_msg_41E = 0.01
    periodicity_msg_44C = 0.05
    periodicity_msg_59E = 0.1

    msgs_and_periodicity = [(msg_3B3,periodicity_msg_3B3),(msg_41E,periodicity_msg_41E),
            (msg_44C,periodicity_msg_44C),(msg_59E,periodicity_msg_59E)]



    for msg,period in msgs_and_periodicity:
        bus.send_periodic(msg, period)
    time.sleep(10)

    print('Block has finished executing. Messages will now be sent at their respective periodicity')




    # 3)
    # bus.send()




    # 4)
    bus.stop_all_periodic_tasks()
    bus.flush_tx_buffer()
    bus.shutdown()
Bryan Oakley
  • 370,779
  • 53
  • 539
  • 685
  • Instead of running the three tests in threads, you can run `test_run()` in a child thread and use the for loop to run the tests inside the function. – acw1668 Jan 04 '22 at 04:53
  • Yes. That suddenly lit up my mind a few hours after I posted this. Thank you for the comment. @acw1668 But out of curiosity, is there a way to do this (4 separate threads with tkinter running indefinetely and the remain threads only run after another without affecting the tkinter GUI – Siddharth Ramachandran Jan 04 '22 at 07:41

0 Answers0