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()