STM32 DFU 烧录完善

This commit is contained in:
2022-05-26 14:20:46 +08:00
parent f564adb140
commit ba98c39c3d
14 changed files with 1023 additions and 2482 deletions

5
.gitignore vendored
View File

@@ -202,4 +202,7 @@ local.properties
/Package/Firmware Installer Setup.exe /Package/Firmware Installer Setup.exe
/Package/Firmware Installer-cache/ /Package/Firmware Installer-cache/
.idea .Package/
.DS_Store
.idea/
firmwareInstaller.bak.py

View File

@@ -1,8 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="PYTHON_MODULE" version="4">
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$" />
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

4
.idea/misc.xml generated
View File

@@ -1,4 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.7 (FirmwareInstaller)" project-jdk-type="Python SDK" />
</project>

View File

@@ -3,12 +3,14 @@
block_cipher = None block_cipher = None
binaries = [
('C:\\Windows\\System32\\libusb0.dll', '.'),
]
a = Analysis(['src\\firmwareInstaller.py'], a = Analysis(['src\\firmwareInstaller.py'],
pathex=['D:\\Work\\Project\\FirmwareInstaller'], pathex=['D:\\Work\\Project\\FirmwareInstaller'],
binaries=[], binaries=binaries,
datas=[('src\\ico.ico', '.')], datas=[('src\\ico.ico', '.')],
hiddenimports=[], hiddenimports=['usb'],
hookspath=[], hookspath=[],
hooksconfig={}, hooksconfig={},
runtime_hooks=[], runtime_hooks=[],

File diff suppressed because it is too large Load Diff

View File

@@ -6,8 +6,8 @@ VSVersionInfo(
ffi=FixedFileInfo( ffi=FixedFileInfo(
# filevers and prodvers should be always a tuple with four items: (1, 2, 3, 4) # filevers and prodvers should be always a tuple with four items: (1, 2, 3, 4)
# Set not needed items to zero 0. # Set not needed items to zero 0.
filevers=(3, 0, 0, 1), filevers=(3, 0, 0, 2),
prodvers=(3, 0, 0, 1), prodvers=(3, 0, 0, 2),
# Contains a bitmask that specifies the valid bits 'flags'r # Contains a bitmask that specifies the valid bits 'flags'r
mask=0x3f, mask=0x3f,
# Contains a bitmask that specifies the Boolean attributes of the file. # Contains a bitmask that specifies the Boolean attributes of the file.
@@ -31,13 +31,13 @@ VSVersionInfo(
u'040904B0', u'040904B0',
[StringStruct(u'CompanyName', u'CreatBot'), [StringStruct(u'CompanyName', u'CreatBot'),
StringStruct(u'FileDescription', u'Hex Installer'), StringStruct(u'FileDescription', u'Hex Installer'),
StringStruct(u'FileVersion', u'3.0.0.1'), StringStruct(u'FileVersion', u'3.0.0.2'),
StringStruct(u'InternalName', u'Firmware Installer'), StringStruct(u'InternalName', u'Firmware Installer'),
StringStruct(u'LegalCopyright', u'Copyright(C) CreatBot 2021. All rights reserved'), StringStruct(u'LegalCopyright', u'Copyright(C) CreatBot 2022. All rights reserved'),
StringStruct(u'LegalTrademarks', u'CreatBot'), StringStruct(u'LegalTrademarks', u'CreatBot'),
StringStruct(u'OriginalFilename', u'Installer.exe'), StringStruct(u'OriginalFilename', u'Installer.exe'),
StringStruct(u'ProductName', u'Firmware Installer'), StringStruct(u'ProductName', u'Firmware Installer'),
StringStruct(u'ProductVersion', u'3.0.0.1')]) StringStruct(u'ProductVersion', u'3.0.0.2')])
]), ]),
VarFileInfo([VarStruct(u'Translation', [1033, 1200])]) VarFileInfo([VarStruct(u'Translation', [1033, 1200])])
] ]

Binary file not shown.

View File

@@ -5,6 +5,7 @@ Created on 2017年8月15日
''' '''
import io import io
# =============================================================================== # ===============================================================================
# Module to read intel hex files into binary data blobs. # Module to read intel hex files into binary data blobs.
# IntelHex files are commonly used to distribute firmware # IntelHex files are commonly used to distribute firmware
@@ -63,4 +64,3 @@ class formatError(Exception):
def __str__(self): def __str__(self):
return repr(self.value) return repr(self.value)

View File

@@ -5,6 +5,7 @@ Created on 2017年8月15日
''' '''
from avr_isp import chipDB from avr_isp import chipDB
# =============================================================================== # ===============================================================================
# General interface for Isp based AVR programmers. # General interface for Isp based AVR programmers.
# The ISP AVR programmer can load firmware into AVR chips. Which are commonly used on 3D printers. # The ISP AVR programmer can load firmware into AVR chips. Which are commonly used on 3D printers.

View File

@@ -8,14 +8,14 @@ Created on 2017年8月15日
# The STK500v2 protocol is used by the ArduinoMega2560 and a few other Arduino platforms to load firmware. # The STK500v2 protocol is used by the ArduinoMega2560 and a few other Arduino platforms to load firmware.
# =============================================================================== # ===============================================================================
import struct, sys import struct
import time import sys
from PyQt5.QtCore import QIODevice, QThread, pyqtSignal from PyQt5.QtCore import QIODevice, QThread, pyqtSignal
from PyQt5.QtSerialPort import QSerialPort, QSerialPortInfo from PyQt5.QtSerialPort import QSerialPort, QSerialPortInfo
from PyQt5.QtWidgets import QApplication from PyQt5.QtWidgets import QApplication
from avr_isp import intelHex, ispBase from avr_isp import intelHex, ispBase
from .errorBase import portError from .errorBase import portError
@@ -88,9 +88,7 @@ class Stk500v2(ispBase.IspBase, QSerialPort):
loadCount = (len(flashData) + pageSize - 1) // pageSize loadCount = (len(flashData) + pageSize - 1) // pageSize
for i in range(0, loadCount): for i in range(0, loadCount):
self.sendMessage( self.sendMessage([0x13, pageSize >> 8, pageSize & 0xFF, 0xc1, 0x0a, 0x40, 0x4c, 0x20, 0x00, 0x00] + flashData[(i * pageSize):(
[0x13, pageSize >> 8, pageSize & 0xFF, 0xc1, 0x0a, 0x40, 0x4c, 0x20, 0x00, 0x00] + flashData[
(i * pageSize):(
i * pageSize + pageSize)]) i * pageSize + pageSize)])
self.progressCallback.emit(i + 1, loadCount * 2) self.progressCallback.emit(i + 1, loadCount * 2)
@@ -191,9 +189,8 @@ class stk500v2Thread(QThread):
self.finished.connect(self.done) self.finished.connect(self.done)
def run(self): def run(self):
try:
self.isWork = True self.isWork = True
try:
self.programmer = Stk500v2() self.programmer = Stk500v2()
if self.callback is not None: if self.callback is not None:
self.programmer.progressCallback.connect(self.callback) self.programmer.progressCallback.connect(self.callback)
@@ -201,26 +198,24 @@ class stk500v2Thread(QThread):
if self.parent is None: if self.parent is None:
runProgrammer(self.port, self.speed, self.filename, self.programmer) runProgrammer(self.port, self.speed, self.filename, self.programmer)
else: else:
self.stateCallback[str].emit(self.tr("Connecting..")) self.stateCallback[str].emit(self.tr("Connecting..."))
self.msleep(200) self.msleep(200)
self.programmer.connect(self.port, self.speed) self.programmer.connect(self.port, self.speed)
self.stateCallback[str].emit(self.tr("Programming...")) self.stateCallback[str].emit(self.tr("Programming..."))
self.programmer.programChip(intelHex.readHex(self.filename)) self.programmer.programChip(intelHex.readHex(self.filename))
except Exception as e: except Exception as e:
if self.isInterruptionRequested(): if self.isInterruptionRequested():
print("Int") print("Int")
else: else:
if self.parent is not None: if self.parent is not None:
self.stateCallback[Exception].emit(e) self.stateCallback[Exception].emit(e)
# while self.isWork: while self.isWork:
# pass # 等待父进程处理异常 pass # 等待父进程处理异常
else: else:
raise e raise e
self.isWork = False self.isWork = False
finally: finally:
self.isWork = False
if self.programmer.isConnected(): if self.programmer.isConnected():
self.programmer.fastReset() self.programmer.fastReset()
self.programmer.close() self.programmer.close()
@@ -266,8 +261,7 @@ def main():
programmer.programChip(intelHex.readHex(sys.argv[2])) programmer.programChip(intelHex.readHex(sys.argv[2]))
else: else:
programmer.connect("COM4") programmer.connect("COM4")
programmer.programChip( programmer.programChip(intelHex.readHex("D:/OneDrive/Desktop/CreatBot F160 01 EN KTC ( AUTO_LEVELING ).hex"))
intelHex.readHex("D:/OneDrive/Desktop/CreatBot F160 01 EN KTC ( AUTO_LEVELING ).hex"))
except portError as e: except portError as e:
print(e.value) print(e.value)
print("PortError: " + str(e)) print("PortError: " + str(e))

View File

@@ -6,13 +6,12 @@ Created on 2017年8月15日
import os import os
import sys import sys
import time
from PyQt5 import QtSerialPort, QtCore, QtWidgets from PyQt5 import QtCore
from PyQt5.Qt import pyqtSignal from PyQt5.Qt import pyqtSignal
from PyQt5.QtCore import QSize, QDir, QTimer from PyQt5.QtCore import QSize, QDir, QTimer
from PyQt5.QtGui import QIcon from PyQt5.QtGui import QIcon
from PyQt5.QtSerialPort import QSerialPortInfo from PyQt5.QtSerialPort import QSerialPortInfo, QSerialPort
from PyQt5.QtWidgets import QApplication, QVBoxLayout, QGroupBox, \ from PyQt5.QtWidgets import QApplication, QVBoxLayout, QGroupBox, \
QRadioButton, QGridLayout, QWidget, QProgressBar, QStatusBar, QComboBox, QLabel, \ QRadioButton, QGridLayout, QWidget, QProgressBar, QStatusBar, QComboBox, QLabel, \
QHBoxLayout, QLineEdit, QPushButton, QFileDialog, QCheckBox QHBoxLayout, QLineEdit, QPushButton, QFileDialog, QCheckBox
@@ -20,8 +19,6 @@ from PyQt5.QtWidgets import QApplication, QVBoxLayout, QGroupBox, \
from avr_isp.intelHex import formatError from avr_isp.intelHex import formatError
from avr_isp.ispBase import IspError from avr_isp.ispBase import IspError
from avr_isp.stk500v2 import stk500v2Thread, portError from avr_isp.stk500v2 import stk500v2Thread, portError
# from DfuseTool import DfuseTool as DFUse
from pydfu import DFUTool as DFUse from pydfu import DFUTool as DFUse
if getattr(sys, 'frozen', False): if getattr(sys, 'frozen', False):
@@ -64,20 +61,17 @@ class mainWindow(QWidget):
def __init__(self): def __init__(self):
super(mainWindow, self).__init__() super(mainWindow, self).__init__()
self.setWindowTitle(self.tr("Firmware Installer")) self.setWindowTitle(self.tr("Firmware Installer" + " V3.1.0"))
self.setWindowIcon(QIcon(os.path.join(bundle_dir, "ico.ico"))) self.setWindowIcon(QIcon(os.path.join(bundle_dir, "ico.ico")))
self.setFixedSize(QSize(480, 240)) self.setFixedSize(QSize(480, 240))
self.setAcceptDrops(True) self.setAcceptDrops(True)
self.portUpdateTimer = QTimer() self.portUpdateTimer = QTimer()
self.portUpdateTimer.timeout.connect(self.portUpdate) self.portUpdateTimer.timeout.connect(self.portUpdate)
self.portUpdateTimer.start(200) self.portUpdateTimer.start(100)
self.autoTimer = QTimer() self.autoTimer = QTimer()
# self.autoTimer.setSingleShot(True) # self.autoTimer.setSingleShot(True)
self.autoTimer.timeout.connect(self.portUpdate) self.autoTimer.timeout.connect(self.installFile)
# self.autoTimer.start(1000)
self.task = None self.task = None
self.initUI() self.initUI()
@@ -135,7 +129,7 @@ class mainWindow(QWidget):
self.autoCheck = QCheckBox(self.tr("Auto Install")) self.autoCheck = QCheckBox(self.tr("Auto Install"))
self.autoTimeLabel = QLabel(self.tr("Idle Time:")) self.autoTimeLabel = QLabel(self.tr("Idle Time:"))
self.autoTimeLabel2 = QLabel(self.tr("s")) self.autoTimeLabel2 = QLabel(self.tr("s"))
self.autoTime = QLineEdit("3") self.autoTime = QLineEdit("2")
self.autoTime.setInputMask("00") self.autoTime.setInputMask("00")
self.autoTime.setMaximumWidth(20) self.autoTime.setMaximumWidth(20)
@@ -174,8 +168,7 @@ class mainWindow(QWidget):
# 计数栏 # 计数栏
self.countBar = QStatusBar() self.countBar = QStatusBar()
self.countBar.setSizeGripEnabled(False) self.countBar.setSizeGripEnabled(False)
self.countBar.setStyleSheet( self.countBar.setStyleSheet("QStatusBar::item { border: 0 } QLabel {border:0; font-size: 14px; font-weight: bold}")
"QStatusBar::item { border: 0 } QLabel {border:0; font-size: 14px; font-weight: bold}")
countSuccessLabel = QLabel("Success: ") countSuccessLabel = QLabel("Success: ")
countFailureLabel = QLabel("Failure: ") countFailureLabel = QLabel("Failure: ")
self.countSuccess = countLabel("0") self.countSuccess = countLabel("0")
@@ -231,9 +224,9 @@ class mainWindow(QWidget):
self.statusBar.messageChanged.connect(self.stateClearAction) self.statusBar.messageChanged.connect(self.stateClearAction)
# 默认选中 # 默认选中
self.autoCheck.click()
self.autoCheck.click()
self.autoRadio.click() self.autoRadio.click()
# self.manualRadio.click()
# self.autoCheck.click()
self.fileBtn.clicked.connect(self.selectFile) self.fileBtn.clicked.connect(self.selectFile)
self.installBtn.clicked.connect(self.installFile) self.installBtn.clicked.connect(self.installFile)
@@ -244,36 +237,24 @@ class mainWindow(QWidget):
def portUpdate(self, forceUpdate=False): def portUpdate(self, forceUpdate=False):
""" Auto 监听端口 """ """ Auto 监听端口 """
print("search port")
if self.autoRadio.isChecked(): if self.autoRadio.isChecked():
self.baudCombo.setCurrentText("115200") self.baudCombo.setCurrentText("115200")
# self.portCombo.addItems(portList()) # self.portCombo.addItems(portList())
# self.portCombo.clear()
port_list = QSerialPortInfo.availablePorts()
for port in port_list:
print(':--:', port.portName(), port.description())
if port.description() not in ["Arduino Mega 2560", "USB-SERIAL CH340"]: # 过滤2560和CH340
continue
self.portCombo.addItem(port.portName() + " (" + port.description() + ")", port.portName())
if len(port_list) > 0:
port = port_list[0]
info = QSerialPortInfo(port)
print(info.productIdentifier())
if info.productIdentifier() == 0:
return
if not self.installBtn.isEnabled():
self.installFile()
else:
currentPortData = self.portCombo.currentData()
if forceUpdate or (currentPortData and currentPortData not in [port.portName() for port in
QSerialPortInfo.availablePorts()]):
self.portCombo.clear() self.portCombo.clear()
for port in QSerialPortInfo.availablePorts(): for port in QSerialPortInfo.availablePorts():
self.portCombo.addItem(port.portName() + " (" + port.description() + ")", port.portName()) if port.description() not in ["Arduino Mega 2560", "USB-SERIAL CH340", "USB 串行设备"]: # 过滤2560和CH340
self.portCombo.setCurrentIndex(self.portCombo.findData(currentPortData)) continue
portInfo = QSerialPortInfo(port)
self.portCombo.addItem(port.portName() + " (" + port.description() + ")", (port.portName(), portInfo.vendorIdentifier()))
else:
currentPortData = self.portCombo.currentText()
if forceUpdate or (currentPortData and currentPortData not in [port.portName() for port in QSerialPortInfo.availablePorts()]):
self.portCombo.clear()
for port in QSerialPortInfo.availablePorts():
portInfo = QSerialPortInfo(port)
self.portCombo.addItem(port.portName() + " (" + port.description() + ")",
(port.portName(), portInfo.vendorIdentifier()))
self.portCombo.setCurrentIndex(self.portCombo.findText(currentPortData))
self.portCombo.setSizeAdjustPolicy(QComboBox.AdjustToContents) self.portCombo.setSizeAdjustPolicy(QComboBox.AdjustToContents)
self.baudCombo.setSizeAdjustPolicy(QComboBox.AdjustToContents) self.baudCombo.setSizeAdjustPolicy(QComboBox.AdjustToContents)
@@ -285,14 +266,6 @@ class mainWindow(QWidget):
if not check and self.autoTimer.remainingTime() > 0: if not check and self.autoTimer.remainingTime() > 0:
self.stopInstall() self.stopInstall()
if check:
# 开启自动安装的端口扫描
self.portUpdateTimer.stop()
self.autoTimer.start(int(self.autoTime.text())*1000)
else:
self.autoTimer.stop()
self.portUpdateTimer.start(200)
def autoTimeChangeAction(self): def autoTimeChangeAction(self):
""" 修改时间间隔 """ """ 修改时间间隔 """
self.autoTime.clearFocus() self.autoTime.clearFocus()
@@ -329,65 +302,35 @@ class mainWindow(QWidget):
self.file.setText(hexFileDialog.selectedFiles()[0]) self.file.setText(hexFileDialog.selectedFiles()[0])
def installFile(self, notFromButton=True): def installFile(self, notFromButton=True):
""" 开始安装 """ if self.portCombo.currentData() is None:
print("-------------------开始安装-------------------") return
# for port in QSerialPortInfo.availablePorts():
# print('port.description===', port.portName())
# print('port.description===', port.description())
# info = QSerialPortInfo(port)
# print(info.productIdentifier())
# print(info.vendorIdentifier())
if self.file.text() == "": if self.file.text() == "":
if not notFromButton: if not notFromButton:
self.selectFile() self.selectFile()
self.installFile(True) self.installFile(True)
else: else:
if self.autoTimer.remainingTime() > 0: if self.autoTimer.remainingTime() != -1:
self.autoTimer.stop() self.autoTimer.stop()
port_list = QSerialPortInfo.availablePorts() self.portBox.setDisabled(True)
if len(port_list) <= 0: self.fileBox.setDisabled(True)
QtWidgets.QMessageBox.about(self, "提示", "没有可用的串口!") self.installBtn.setDisabled(True)
return
port = port_list[0] self.progress.show()
info = QSerialPortInfo(port) self.resize()
port_Name = None info = self.portCombo.currentData()
baud_rate = None if info[1] == 1155:
if self.manualRadio.isChecked(): self.stopBtn.setEnabled(False)
if self.portCombo.currentData() is None:
QtWidgets.QMessageBox.about(self, "提示", "请选择串口设备")
return
else:
port_Name = self.portCombo.currentData()
baud_rate = int(self.baudCombo.currentText())
else:
port_Name = info.portName()
baud_rate = QtSerialPort.QSerialPort.Baud115200
print("port:", port_Name)
print("baudCombo:", baud_rate)
print(info.portName())
print(info.description())
print(info.productIdentifier())
print(info.vendorIdentifier())
if info.productIdentifier() == 0:
self.autoTimer.start(1000)
pass
if info.vendorIdentifier() == 1155:
print("------命令开启DFU模式 start------")
self.statusBar.showMessage("Serial to DFU...") self.statusBar.showMessage("Serial to DFU...")
serial = QtSerialPort.QSerialPort(self) serial = QSerialPort(self)
serial.setPortName(port_Name) serial.setPortName(info[0])
serial.setBaudRate(baud_rate) serial.setBaudRate(QSerialPort.Baud115200)
serial.setDataBits(QtSerialPort.QSerialPort.Data8) serial.setDataBits(QSerialPort.Data8)
serial.setParity(QtSerialPort.QSerialPort.NoParity) serial.setParity(QSerialPort.NoParity)
serial.setStopBits(QtSerialPort.QSerialPort.OneStop) serial.setStopBits(QSerialPort.OneStop)
serial.setFlowControl(QtSerialPort.QSerialPort.NoFlowControl) serial.setFlowControl(QSerialPort.NoFlowControl)
if not serial.open(QtCore.QIODevice.ReadWrite): if not serial.open(QtCore.QIODevice.ReadWrite):
# QtWidgets.QMessageBox.about(self, "提示", "无法打开串口!") # QtWidgets.QMessageBox.about(self, "提示", "无法打开串口!")
@@ -396,25 +339,35 @@ class mainWindow(QWidget):
data = bytes("M9999\r", encoding='utf-8') data = bytes("M9999\r", encoding='utf-8')
data = QtCore.QByteArray(data) data = QtCore.QByteArray(data)
serial.write(data) serial.write(data)
print("------命令开启DFU模式 end------")
self.statusBar.showMessage("Serial to dfu...") self.statusBar.showMessage("Serial to dfu...")
self.task = DFUse(self, self.file.text(), self.progressUpdate) self.task = DFUse(self, self.portCombo.currentData()[0], int(self.baudCombo.currentText()), self.file.text(),
self.progressUpdate)
self.task.stateCallback[str].connect(self.stateUpdate) self.task.stateCallback[str].connect(self.stateUpdate)
self.task.stateCallback[Exception].connect(self.stateUpdate) self.task.stateCallback[Exception].connect(self.stateUpdate)
self.task.finished.connect(self.autoAction) # 检查是否自动烧写,并启动。 self.task.finished.connect(self.autoAction) # 检查是否自动烧写,并启动。
# self.task.start() # self.task.start()
elif info.vendorIdentifier() != 0: elif info[1] != 0:
self.task = stk500v2Thread(self, self.portCombo.currentData(), int(self.baudCombo.currentText()), self.stopBtn.setEnabled(True)
self.task = stk500v2Thread(self, info[0], int(self.baudCombo.currentText()),
self.file.text(), self.progressUpdate) self.file.text(), self.progressUpdate)
self.task.stateCallback[str].connect(self.stateUpdate) self.task.stateCallback[str].connect(self.stateUpdate)
self.task.stateCallback[Exception].connect(self.stateUpdate) self.task.stateCallback[Exception].connect(self.stateUpdate)
self.task.finished.connect(self.autoAction) self.task.finished.connect(self.autoAction)
self.task.start() self.task.start()
# 开始烧录刷新UI return
# self.statusBar.showMessage(" ")
if self.file.text() == "":
if not notFromButton:
self.selectFile()
self.installFile(True)
else:
if self.autoTimer.remainingTime() != -1:
self.autoTimer.stop()
self.portBox.setDisabled(True) self.portBox.setDisabled(True)
self.fileBox.setDisabled(True) self.fileBox.setDisabled(True)
self.installBtn.setDisabled(True) self.installBtn.setDisabled(True)
@@ -422,6 +375,14 @@ class mainWindow(QWidget):
self.progress.show() self.progress.show()
self.resize() self.resize()
self.task = DFUse(self, self.portCombo.currentData()[0], int(self.baudCombo.currentText()), self.file.text(),
self.progressUpdate)
self.task.stateCallback[str].connect(self.stateUpdate)
self.task.stateCallback[Exception].connect(self.stateUpdate)
self.task.finished.connect(self.autoAction)
self.task.start()
self.statusBar.showMessage(" ")
def stopInstall(self, succeed=False, autoInstall=False): def stopInstall(self, succeed=False, autoInstall=False):
""" 停止自动安装 """ """ 停止自动安装 """
if autoInstall: if autoInstall:
@@ -440,8 +401,8 @@ class mainWindow(QWidget):
self.countSuccess.setText(str(int(self.countSuccess.text()) + 1)) self.countSuccess.setText(str(int(self.countSuccess.text()) + 1))
self.task = None self.task = None
else: else:
# if self.autoTimer.remainingTime() != -1: if self.autoTimer.remainingTime() != -1:
# self.autoTimer.stop() self.autoTimer.stop()
if self.task is not None and self.task.isRunning(): if self.task is not None and self.task.isRunning():
self.task.finished.disconnect() self.task.finished.disconnect()
if self.task.isReady(): if self.task.isReady():
@@ -459,14 +420,10 @@ class mainWindow(QWidget):
def autoAction(self): def autoAction(self):
""" 上一个任务结束后,开启新的烧录任务 """ """ 上一个任务结束后,开启新的烧录任务 """
self.task = None self.stopBtn.setEnabled(True)
self.statusBar.showMessage("Done!")
self.stopInstall(True, self.autoCheck.isChecked()) self.stopInstall(True, self.autoCheck.isChecked())
# 开启自动安装 # 开启自动安装
if self.autoCheck.isChecked(): if self.autoCheck.isChecked():
if self.autoTimer.remainingTime() > 0:
self.autoTimer.stop()
self.autoTimer.start(int(self.autoTime.text()) * 1000) self.autoTimer.start(int(self.autoTime.text()) * 1000)
def resize(self): def resize(self):
@@ -481,31 +438,24 @@ class mainWindow(QWidget):
""" 安装状态 """ """ 安装状态 """
self.tryAgainLabel.setHidden(True) self.tryAgainLabel.setHidden(True)
self.tryAgain.setHidden(True) self.tryAgain.setHidden(True)
if self.task.isReady(): # if self.task.isReady():
self.tryAgain.setText("0") # self.tryAgain.setText("0")
print(stateOrError, str)
if type(stateOrError) == str: if type(stateOrError) == str:
print("222---")
# self.statusBar.setStyleSheet("QStatusBar::item { border: 0 } QLabel {color: red; font-weight: bold}") # self.statusBar.setStyleSheet("QStatusBar::item { border: 0 } QLabel {color: red; font-weight: bold}")
self.statusBar.setStyleSheet( self.statusBar.setStyleSheet(
"QStatusBar {font-weight: bold; color: black} QStatusBar::item { border: 0 } QLabel {font-weight: bold}") "QStatusBar {font-weight: bold; color: black} QStatusBar::item { border: 0 } QLabel {font-weight: bold}")
if self.task is not None and not self.task.isWork and not self.autoCheck.isChecked(): if self.task is not None and not self.task.isWork and not self.autoCheck.isChecked():
print("statusBar---")
self.statusBar.showMessage(stateOrError, 3000) self.statusBar.showMessage(stateOrError, 3000)
else: else:
print("else---")
self.statusBar.showMessage(stateOrError) self.statusBar.showMessage(stateOrError)
else: else:
print("333---")
self.task.requestInterruption() self.task.requestInterruption()
self.statusBar.setStyleSheet( self.statusBar.setStyleSheet(
"QStatusBar {font-weight: bold; color: red} QStatusBar::item { border: 0 } QLabel {font-weight: bold; color: red}") "QStatusBar {font-weight: bold; color: red} QStatusBar::item { border: 0 } QLabel {font-weight: bold; color: red}")
if type(stateOrError) == portError: if type(stateOrError) == portError:
if (stateOrError.value in [portError.errorInvalid, portError.errorBusy]) and ( if (stateOrError.value in [portError.errorInvalid, portError.errorBusy]) and (int(self.tryAgain.text()) < 20):
int(self.tryAgain.text()) < 20):
self.statusBar.showMessage("PortError: " + str(stateOrError)) self.statusBar.showMessage("PortError: " + str(stateOrError))
self.tryAgain.setText(str(int(self.tryAgain.text()) + 1)) self.tryAgain.setText(str(int(self.tryAgain.text()) + 1))
self.tryAgainLabel.setVisible(True) self.tryAgainLabel.setVisible(True)
@@ -531,7 +481,6 @@ class mainWindow(QWidget):
else: else:
self.statusBar.showMessage("Error: " + str(stateOrError), 5000) self.statusBar.showMessage("Error: " + str(stateOrError), 5000)
self.stopInstall() self.stopInstall()
print("1111---")
self.task.isWork = False self.task.isWork = False
self.task.wait(100) self.task.wait(100)
@@ -539,7 +488,6 @@ class mainWindow(QWidget):
if __name__ == '__main__': if __name__ == '__main__':
app = QApplication(sys.argv) app = QApplication(sys.argv)
win = mainWindow() win = mainWindow()

View File

@@ -18,10 +18,12 @@ import collections
import inspect import inspect
import re import re
import struct import struct
import sys, time import sys
import time
import zlib
import usb.core import usb.core
import usb.util import usb.util
import zlib
# USB request __TIMEOUT # USB request __TIMEOUT
__TIMEOUT = 4000 __TIMEOUT = 4000
@@ -658,24 +660,213 @@ def main():
# if __name__ == "__main__": # if __name__ == "__main__":
# main() # main()
from avr_isp.errorBase import portError from PyQt5.QtCore import QIODevice, QThread, pyqtSignal, QByteArray
from PyQt5.QtCore import QIODevice, QThread, pyqtSignal
from PyQt5.QtSerialPort import QSerialPort, QSerialPortInfo from PyQt5.QtSerialPort import QSerialPort, QSerialPortInfo
from PyQt5.QtWidgets import QApplication from PyQt5.QtWidgets import QApplication
from avr_isp import ispBase
from avr_isp.errorBase import portError
class STM32Dev(ispBase.IspBase, QSerialPort):
progressCallback = pyqtSignal(int, int)
def __init__(self):
super(STM32Dev, self).__init__()
self.seq = 1
self.lastAddr = -1
self.portInfo = None
def connect(self, port='COM4', speed=115200):
print("connect", port)
self.portInfo = QSerialPortInfo(port)
print("portInfo", self.portInfo)
self.setPortName(port)
# self.setBaudRate(speed)
# self.setPortName("COM3")
self.setBaudRate(QSerialPort.Baud115200)
self.setDataBits(QSerialPort.Data8)
self.setParity(QSerialPort.NoParity)
self.setStopBits(QSerialPort.OneStop)
self.setFlowControl(QSerialPort.NoFlowControl)
if self.portInfo.isNull():
raise portError(portError.errorInvalid, port)
else:
if self.portInfo.isBusy():
raise portError(portError.errorBusy, port)
else:
if self.open(QIODevice.ReadWrite):
# self.setBreakEnabled()
print("open")
# self.entryISP()
print("open--end")
else:
raise portError(portError.errorOpen, port)
def close(self):
super(STM32Dev, self).close()
self.portInfo = None
def serial_DFU(self):
print("serial_DFU")
# if not self.open(QIODevice.ReadWrite):
# # QtWidgets.QMessageBox.about(self, "提示", "无法打开串口!")
# return
print("1111")
data = bytes("M9999\r", encoding='utf-8')
data = QByteArray(data)
print("2222")
# self.write(data)
print(self.write(data))
print("serial_DFU---end")
self.close()
def entryISP(self):
self.seq = 1
# Reset the controller
self.setDataTerminalReady(True)
QThread.msleep(100)
self.setDataTerminalReady(False)
QThread.msleep(200)
self.clear()
print("=====")
recv = self.sendMessage([1])[3:]
if "".join([chr(c) for c in recv]) != "AVRISP_2":
raise ispBase.IspError("Unkonwn bootloaders!")
if self.sendMessage([0x10, 0xc8, 0x64, 0x19, 0x20, 0x00, 0x53, 0x03, 0xac, 0x53, 0x00, 0x00]) != [0x10, 0x00]:
raise ispBase.IspError("Failed to enter programming mode!")
def leaveISP(self):
if self.portInfo is not None:
if self.sendMessage([0x11]) != [0x11, 0x00]:
raise ispBase.IspError("Failed to leave programming mode!")
def isConnected(self):
return self.isOpen()
def sendISP(self, data):
recv = self.sendMessage([0x1D, 4, 4, 0, data[0], data[1], data[2], data[3]])
return recv[2:6]
def writeFlash(self, flashData):
# Set load addr to 0, in case we have more then 64k flash we need to enable the address extension
pageSize = self.chip['pageSize'] * 2
flashSize = pageSize * self.chip['pageCount']
if flashSize > 0xFFFF:
self.sendMessage([0x06, 0x80, 0x00, 0x00, 0x00])
else:
self.sendMessage([0x06, 0x00, 0x00, 0x00, 0x00])
loadCount = (len(flashData) + pageSize - 1) // pageSize
for i in range(0, loadCount):
self.sendMessage([0x13, pageSize >> 8, pageSize & 0xFF, 0xc1, 0x0a, 0x40, 0x4c, 0x20, 0x00, 0x00] + flashData[(i * pageSize):(
i * pageSize + pageSize)])
self.progressCallback.emit(i + 1, loadCount * 2)
def verifyFlash(self, flashData):
# Set load addr to 0, in case we have more then 64k flash we need to enable the address extension
flashSize = self.chip['pageSize'] * 2 * self.chip['pageCount']
if flashSize > 0xFFFF:
self.sendMessage([0x06, 0x80, 0x00, 0x00, 0x00])
else:
self.sendMessage([0x06, 0x00, 0x00, 0x00, 0x00])
loadCount = (len(flashData) + 0xFF) // 0x100
for i in range(0, loadCount):
recv = self.sendMessage([0x14, 0x01, 0x00, 0x20])[2:0x102]
self.progressCallback.emit(loadCount + i + 1, loadCount * 2)
for j in range(0, 0x100):
if i * 0x100 + j < len(flashData) and flashData[i * 0x100 + j] != recv[j]:
raise ispBase.IspError('Verify error at: 0x%x' % (i * 0x100 + j))
def fastReset(self):
QThread.msleep(50)
self.setDataTerminalReady(True)
self.setDataTerminalReady(False)
def sendMessage(self, data):
message = struct.pack(">BBHB", 0x1B, self.seq, len(data), 0x0E)
for c in data:
message += struct.pack(">B", c)
checksum = 0
for c in message:
checksum ^= c
message += struct.pack(">B", checksum)
try:
print("----00")
self.write(message)
self.flush()
print("----11")
except:
raise ispBase.IspError("Serial send timeout")
self.seq = (self.seq + 1) & 0xFF
print("----222")
# time.sleep(1)
if self.waitForReadyRead(1000):
print("----33")
return self.recvMessage()
else:
print("----44")
raise ispBase.IspError("Serial recv timeout")
def recvMessage(self):
state = 'Start'
checksum = 0
while True:
s = self.read(1)
if len(s) < 1:
if self.waitForReadyRead(20):
continue
else:
raise ispBase.IspError("Serial read timeout")
b = struct.unpack(">B", s)[0]
checksum ^= b
if state == 'Start':
if b == 0x1B:
state = 'GetSeq'
checksum = 0x1B
elif state == 'GetSeq':
state = 'MsgSize1'
elif state == 'MsgSize1':
msgSize = b << 8
state = 'MsgSize2'
elif state == 'MsgSize2':
msgSize |= b
state = 'Token'
elif state == 'Token':
if b != 0x0E:
state = 'Start'
else:
state = 'Data'
data = []
elif state == 'Data':
data.append(b)
if len(data) == msgSize:
state = 'Checksum'
elif state == 'Checksum':
if checksum != 0:
state = 'Start'
else:
return data
class DFUTool(QThread): class DFUTool(QThread):
print("DFUTool(QThread)") print("DFUTool(QThread)")
stateCallback = pyqtSignal([str], [Exception]) stateCallback = pyqtSignal([str], [Exception])
progressCallback = pyqtSignal(int, int) progressCallback = pyqtSignal(int, int)
def __init__(self, parent, filename, callback=None): def __init__(self, parent, port, speed, filename, callback=None):
super(DFUTool, self).__init__() super(DFUTool, self).__init__()
print("----------------------")
self.parent = parent self.parent = parent
self.port = port
self.speed = speed
self.filename = filename self.filename = filename
self.progress = callback self.callback = callback
self.programmer = None
self.isWork = False self.isWork = False
self.finished.connect(self.done) self.finished.connect(self.done)
@@ -721,6 +912,7 @@ class DFUTool(QThread):
def w(state): def w(state):
if state is False: if state is False:
self.stateCallback[Exception].emit(portError(portError.errorOpen, port))
self.stateCallback[str].emit("Done!") self.stateCallback[str].emit("Done!")
self.quit() self.quit()
return return
@@ -737,30 +929,40 @@ class DFUTool(QThread):
self.thread = DFUSearch(self, kwargs=kwargs) self.thread = DFUSearch(self, kwargs=kwargs)
self.thread.searchResults.connect(w) # 异步完成后执行函数w self.thread.searchResults.connect(w) # 异步完成后执行函数w
self.thread.start() self.thread.start()
self.isWork = True
def cl_progress(self, addr, offset, size): def cl_progress(self, addr, offset, size):
"""Prints a progress report suitable for use on the command line.""" """Prints a progress report suitable for use on the command line."""
print("offset", offset, "size", size)
self.progressCallback.emit(offset, size) self.progressCallback.emit(offset, size)
def disconnect(self, QMetaObject_Connection=None):
print("QMetaObject_Connection")
def run(self): def run(self):
if self.progress is not None: self.isWork = True
self.progressCallback.connect(self.progress) try:
print(self.args)
self.stateCallback[str].emit("read fils")
with open(self.args.path, "rb") as fin: with open(self.args.path, "rb") as fin:
dfu_file = fin.read() dfu_file = fin.read()
if dfu_file is None: if dfu_file is None:
print("file is None") print("file is None")
return return
self.isWork = True
elem = {"addr": 134217728, "size": len(dfu_file), "data": dfu_file} elem = {"addr": 134217728, "size": len(dfu_file), "data": dfu_file}
try: self.programmer = STM32Dev()
self.stateCallback[str].emit("Write file...")
if self.callback is not None:
self.progressCallback.connect(self.callback)
if self.parent is None:
pass
else:
self.stateCallback[str].emit(self.tr("Programming..."))
# self.programmer.
write_elements([elem], self.args.mass_erase, progress=self.cl_progress) write_elements([elem], self.args.mass_erase, progress=self.cl_progress)
exit_dfu() # 退出DFU模式
except Exception as err: except Exception as err:
if self.isInterruptionRequested(): if self.isInterruptionRequested():
print("int") print("int")
@@ -773,16 +975,13 @@ class DFUTool(QThread):
raise err raise err
self.isWork = False self.isWork = False
finally: finally:
self.isWork = False self.stateCallback[str].emit("Done!")
self.stateCallback[str].emit("Exiting DFU...") self.programmer = None
print("Exiting DFU...")
exit_dfu()
# 退出DFU模式
print("Done...")
self.ude = None
def isReady(self): def isReady(self):
return True return True
return self.programmer is not None and self.programmer.isConnected()
try: try:
status = get_status() status = get_status()
print(status) print(status)
@@ -807,6 +1006,9 @@ class DFUTool(QThread):
print("Failure!") print("Failure!")
def terminate(self): def terminate(self):
if self.thread.isRunning():
self.thread.exit()
self.requestInterruption() self.requestInterruption()
return super(DFUTool, self).terminate() return super(DFUTool, self).terminate()
@@ -830,11 +1032,11 @@ class DFUSearch(QThread):
devices = get_dfu_devices(**self.kwargs) devices = get_dfu_devices(**self.kwargs)
attempts += 1 attempts += 1
print("搜索DFU设备", attempts) print("搜索DFU设备", attempts)
if attempts > 10: if attempts > 20:
self.searchResults.emit(False) self.searchResults.emit(False)
self.quit() self.quit()
return return
time.sleep(2) time.sleep(1)
self.searchResults.emit(True) self.searchResults.emit(True)