I have a job to create a stm mcu downloader using uart communication.
I used to python and pyqt5.
Results were bad because of the program GUI freezing when starting the download. (download progress is well)
So I changed the code to the way I use Qthread.
But nothing change.
I have 2 Questions.
Am I use Qthread correctly?
How can I fix GUI freezing when start download?
Attach the code below
from PyQt5.QtWidgets import QMainWindow, QApplication, QFileDialog, QTextBrowser
from PyQt5 import uic
from PyQt5.QtCore import *
import sys, serial, time, struct, os
form_class = uic.loadUiType('USART_Downloader.ui')[0]
class Worker(QObject):
ports=['COM%s'%(i+1)for i in range(256)]
check_connect = 0
serial = serial.Serial()
time_instance = 0.00008
finished = pyqtSignal(list)
finished2 = pyqtSignal(str)
finished3 = pyqtSignal(str)
finished4 = pyqtSignal(int)
@pyqtSlot()
def Find_Com(self):
result = []
for i in self.ports:
try:
temp = serial.Serial(i)
temp.close()
result.append(i)
except serial.SerialException:
pass
self.finished.emit(result)
@pyqtSlot(str)
def Apply_Com(self, COM_Port):
self.check_connect=0
self.serial.close()
try :
self.serial = serial.Serial(COM_Port, 115200, timeout = 1)
self.check_connect = 1
self.finished2.emit('Successfully Port Connection')
except serial.SerialException:
self.finished2.emit('Failure Port Connection')
if self.check_connect :
self.serial.write(b'\x7F')
time.sleep(self.time_instance)
res = self.serial.read()
if res == b'\x79' :
self.finished2.emit('Successfully Enter Boot Mode')
else:
self.finished2.emit('Failure Enter Boot Mode')
@pyqtSlot(str)
def Download_Flash(self, fileName):
if self.check_connect:
self.serial.write(b'\x44')
time.sleep(self.time_instance)
self.serial.write(b'\xBB')
time.sleep(self.time_instance)
res = self.serial.read()
if res == b'\x79' :
self.finished3.emit('Erasing')
else:
self.finished3.emit('Failure Enter Erase Flash')
return
self.serial.write(b'\xFF')
time.sleep(self.time_instance)
self.serial.write(b'\xFF')
time.sleep(self.time_instance)
self.serial.write(b'\x00')
time.sleep(self.time_instance)
res = self.serial.read()
if res == b'\x79' :
self.finished3.emit('Successfully Erase Flash')
else:
self.finished3.emit('Failure Enter Erase Flash')
return
else :
self.finished3.emit('Need USART Connection')
Bit_Num = 256
f = open(fileName, 'rb')
download_binary = f.read()
download_binary_len = len(download_binary)
f.close()
start_address = b'\x00\x00\x00\x08'
total_data = []
while(True):
if(download_binary_len > Bit_Num):
total_data.append(Bit_Num)
download_binary_len -= Bit_Num
elif(download_binary_len > 0):
total_data.append(download_binary_len)
download_binary_len = 0
else:
break
self.finished3.emit('Downloading')
for i, k in enumerate(total_data):
self.serial.write(b'\x31')
time.sleep(self.time_instance)
self.serial.write(b'\xCE')
time.sleep(self.time_instance)
res = self.serial.read()
if res == b'\x79' :
pass
else:
self.finished3.emit('Failure Download1')
return
self.serial.write(start_address[3:4])
time.sleep(self.time_instance)
self.serial.write(start_address[2:3])
time.sleep(self.time_instance)
self.serial.write(start_address[1:2])
time.sleep(self.time_instance)
self.serial.write(start_address[0:1])
time.sleep(self.time_instance)
temp2 = struct.unpack('4B', start_address)
check_sum = temp2[0] ^ temp2[1] ^ temp2[2] ^ temp2[3]
check_sum = struct.pack('B', check_sum)
self.serial.write(check_sum)
time.sleep(self.time_instance)
res = self.serial.read()
if res == b'\x79' :
pass
else:
self.finished3.emit('Failure Download2')
return
check_sum = (k-1)
self.serial.write(struct.pack('B', check_sum))
time.sleep(self.time_instance)
for j in range(k):
self.serial.write(download_binary[(i*Bit_Num)+j:(i*Bit_Num)+j+1])
time.sleep(self.time_instance)
for j in download_binary[(i*Bit_Num):(i*Bit_Num)+j+1] :
check_sum = check_sum ^ j
check_sum = struct.pack('B', check_sum)
self.serial.write(check_sum)
time.sleep(self.time_instance)
res = self.serial.read()
if res == b'\x79' :
pass
else:
self.finished3.emit('Failure Download3')
return
temp3 = struct.unpack('i', start_address)[0]
temp3 = temp3 + Bit_Num
start_address = struct.pack('i', temp3)
self.finished4.emit(i/(len(total_data)-1)*100)
self.finished3.emit('Success Download')
class MyWindowClass(QMainWindow, form_class):
def __init__(self, parent=None):
QMainWindow.__init__(self, parent)
self.setupUi(self)
self.fileName = ''
self.worker_thread = QThread()
self.worker = Worker()
self.worker.moveToThread(self.worker_thread)
self.worker_thread.start()
self.worker.finished.connect(self.Refresh_Com)
self.worker.finished2.connect(self.Print_textBrowser)
self.worker.finished3.connect(self.Print_textBrowser_3)
self.worker.finished4.connect(self.Set_ProgressBar)
self.pushButton.clicked.connect(self.Find_Binary)
self.pushButton_2.clicked.connect(lambda:self.worker.Download_Flash(self.fileName))
self.pushButton_3.clicked.connect(lambda:self.worker.Apply_Com(self.comboBox.currentText()))
self.pushButton_4.clicked.connect(self.worker.Find_Com)
self.textBrowser.setAcceptRichText(True)
self.textBrowser.setOpenExternalLinks(True)
self.textBrowser_3.setAcceptRichText(True)
self.textBrowser_3.setOpenExternalLinks(True)
self.progressBar.reset()
self.worker.Find_Com()
@pyqtSlot(list)
def Refresh_Com(self, result):
self.comboBox.clear()
for i in result:
self.comboBox.addItem(i)
self.textBrowser.append('COM Port Refresh Done')
@pyqtSlot(str)
def Print_textBrowser(self, text):
self.textBrowser.append(text)
@pyqtSlot(str)
def Print_textBrowser_3(self, text):
self.textBrowser_3.append(text)
@pyqtSlot(int)
def Set_ProgressBar(self, percent):
self.progressBar.setValue(percent)
def Find_Binary(self):
options = QFileDialog.Options()
self.fileName, _ = QFileDialog.getOpenFileName(self, "QFileDialog.getOpenFileName()", "", "Binary Files (*.bin)", options=options)
self.lineEdit.setText(self.fileName)
if __name__ == "__main__":
app = QApplication(sys.argv)
myWindow = MyWindowClass()
myWindow.show()
app.exec_()