mirror of
https://github.com/DarkMatterCore/nxdumptool.git
synced 2024-11-26 12:12:02 +00:00
Fix crashes related to tqdm.
Use our own child window with strings generated by tqdm.format_meter() instead of relying on tqdm_tk.
This commit is contained in:
parent
651e5d5f87
commit
e70979248a
2 changed files with 96 additions and 29 deletions
10
.gitignore
vendored
10
.gitignore
vendored
|
@ -1,4 +1,6 @@
|
||||||
build
|
build
|
||||||
|
__pycache__
|
||||||
|
dist
|
||||||
*.elf
|
*.elf
|
||||||
*.nacp
|
*.nacp
|
||||||
*.nro
|
*.nro
|
||||||
|
@ -7,11 +9,7 @@ build
|
||||||
*.pfs0
|
*.pfs0
|
||||||
*.lst
|
*.lst
|
||||||
*.tar.bz2
|
*.tar.bz2
|
||||||
|
*.log
|
||||||
|
*.spec
|
||||||
/code_templates/tmp/*
|
/code_templates/tmp/*
|
||||||
/source/main.c
|
/source/main.c
|
||||||
*.log
|
|
||||||
|
|
||||||
# Clion files
|
|
||||||
.idea
|
|
||||||
cmake-build-debug
|
|
||||||
CMakeLists.txt
|
|
||||||
|
|
115
nxdt_host.pyw
115
nxdt_host.pyw
|
@ -40,11 +40,13 @@ import time
|
||||||
import struct
|
import struct
|
||||||
import usb.core
|
import usb.core
|
||||||
import usb.util
|
import usb.util
|
||||||
|
import warnings
|
||||||
|
|
||||||
import tkinter as tk
|
import tkinter as tk
|
||||||
|
import tkinter.ttk as ttk
|
||||||
from tkinter import filedialog, messagebox, font, scrolledtext
|
from tkinter import filedialog, messagebox, font, scrolledtext
|
||||||
|
|
||||||
from tqdm.tk import trange, tqdm_tk
|
from tqdm import tqdm
|
||||||
|
|
||||||
import base64
|
import base64
|
||||||
import io
|
import io
|
||||||
|
@ -249,6 +251,76 @@ class LogConsole:
|
||||||
|
|
||||||
self.frame.after(100, self.poll_log_queue)
|
self.frame.after(100, self.poll_log_queue)
|
||||||
|
|
||||||
|
# Loosely based on tk.py from tqdm.
|
||||||
|
class ProgressBar:
|
||||||
|
def __init__(self, total, prefix='', unit='B', bar_format=None, tk_parent=None, window_title='', window_resize=False, window_protocol=None):
|
||||||
|
if (tk_parent is None) or (total <= 0):
|
||||||
|
raise Exception('Invalid arguments!')
|
||||||
|
|
||||||
|
self.n = 0
|
||||||
|
self.total = total
|
||||||
|
self.prefix = prefix
|
||||||
|
self.unit = unit
|
||||||
|
self.bar_format = bar_format
|
||||||
|
|
||||||
|
self.tk_parent = tk_parent
|
||||||
|
self.tk_window = tk.Toplevel(self.tk_parent)
|
||||||
|
|
||||||
|
if window_title:
|
||||||
|
self.tk_window.title(window_title)
|
||||||
|
|
||||||
|
self.tk_window.resizable(window_resize, window_resize)
|
||||||
|
|
||||||
|
if window_protocol:
|
||||||
|
self.tk_window.protocol('WM_DELETE_WINDOW', window_protocol)
|
||||||
|
|
||||||
|
self.tk_window.attributes('-topmost', True)
|
||||||
|
self.tk_window.after(0, lambda: self.tk_window.attributes('-topmost', False))
|
||||||
|
|
||||||
|
pbar_frame = ttk.Frame(self.tk_window, padding=5)
|
||||||
|
pbar_frame.pack()
|
||||||
|
|
||||||
|
self.tk_text_var = tk.StringVar(self.tk_window)
|
||||||
|
tk_label = ttk.Label(pbar_frame, textvariable=self.tk_text_var, wraplength=600, anchor='center', justify='center')
|
||||||
|
tk_label.pack()
|
||||||
|
|
||||||
|
self.tk_n_var = tk.DoubleVar(self.tk_window, value=0)
|
||||||
|
self.tk_pbar = ttk.Progressbar(pbar_frame, variable=self.tk_n_var, length=450)
|
||||||
|
self.tk_pbar.configure(maximum=self.total, mode='determinate')
|
||||||
|
self.tk_pbar.pack()
|
||||||
|
|
||||||
|
self.start = time.time()
|
||||||
|
|
||||||
|
self.update(0)
|
||||||
|
|
||||||
|
def close(self):
|
||||||
|
self.tk_parent.after(0, self.tk_window.destroy)
|
||||||
|
|
||||||
|
def update(self, n):
|
||||||
|
if (self.n + n) > self.total:
|
||||||
|
return
|
||||||
|
|
||||||
|
self.n += n
|
||||||
|
elapsed = (time.time() - self.start)
|
||||||
|
|
||||||
|
msg = tqdm.format_meter(n=self.n, total=self.total, elapsed=elapsed, prefix=self.prefix, unit=self.unit, bar_format=self.bar_format)
|
||||||
|
|
||||||
|
self.tk_text_var.set(msg)
|
||||||
|
self.tk_n_var.set(self.n)
|
||||||
|
|
||||||
|
def reset(self, total):
|
||||||
|
if (total <= 0):
|
||||||
|
raise Exception('Invalid total value!')
|
||||||
|
|
||||||
|
self.n = 0
|
||||||
|
self.total = total
|
||||||
|
|
||||||
|
self.tk_pbar.configure(maximum=self.total, mode='determinate')
|
||||||
|
|
||||||
|
self.start = time.time()
|
||||||
|
|
||||||
|
self.update(0)
|
||||||
|
|
||||||
def utilsIsValueAlignedToEndpointPacketSize(value):
|
def utilsIsValueAlignedToEndpointPacketSize(value):
|
||||||
return bool((value & (g_usbEpMaxPacketSize - 1)) == 0)
|
return bool((value & (g_usbEpMaxPacketSize - 1)) == 0)
|
||||||
|
|
||||||
|
@ -496,20 +568,17 @@ def usbHandleSendFileProperties(cmd_block):
|
||||||
|
|
||||||
# Initialize progress bar.
|
# Initialize progress bar.
|
||||||
(unit, unit_divisor) = utilsGetSizeUnitAndDivisor(file_size)
|
(unit, unit_divisor) = utilsGetSizeUnitAndDivisor(file_size)
|
||||||
|
total = (float(file_size) / unit_divisor)
|
||||||
|
|
||||||
idx = filename.rfind(os.path.sep)
|
idx = filename.rfind(os.path.sep)
|
||||||
bar_format_filename = (filename[idx+1:] if (idx >= 0) else filename)
|
prefix_filename = (filename[idx+1:] if (idx >= 0) else filename)
|
||||||
|
|
||||||
bar_format = ('Current file: "%s".\n' % (bar_format_filename))
|
prefix = ('Current file: "%s".\n' % (prefix_filename))
|
||||||
bar_format += 'Use your console to cancel the file transfer if you wish to do so.\n\n'
|
prefix += 'Use your console to cancel the file transfer if you wish to do so.\n\n'
|
||||||
bar_format += '{percentage:.2f}% - {n:.2f} / {total:.2f} {unit}\nElapsed time: {elapsed}. Remaining time: {remaining}.\nSpeed: {rate_fmt}.'
|
|
||||||
|
|
||||||
pbar = tqdm_tk(total=(float(file_size) / unit_divisor), unit=unit, bar_format=bar_format, grab=False, tk_parent=g_tkRoot)
|
bar_format = '{desc}{percentage:.2f}% - {n:.2f} / {total:.2f} {unit}\nElapsed time: {elapsed}. Remaining time: {remaining}.\nSpeed: {rate_fmt}.'
|
||||||
pbar._tk_window.title('File transfer')
|
|
||||||
pbar._tk_window.resizable(False, False)
|
|
||||||
pbar._tk_window.protocol('WM_DELETE_WINDOW', uiHandleExitProtocolStub)
|
|
||||||
|
|
||||||
start_time = time.time()
|
pbar = ProgressBar(total, prefix, unit, bar_format, g_tkRoot, 'File transfer', False, uiHandleExitProtocolStub)
|
||||||
|
|
||||||
def cancelTransfer():
|
def cancelTransfer():
|
||||||
# Cancel file transfer.
|
# Cancel file transfer.
|
||||||
|
@ -517,7 +586,6 @@ def usbHandleSendFileProperties(cmd_block):
|
||||||
os.remove(fullpath)
|
os.remove(fullpath)
|
||||||
utilsResetNspInfo()
|
utilsResetNspInfo()
|
||||||
pbar.close()
|
pbar.close()
|
||||||
pbar._tk_window.destroy()
|
|
||||||
|
|
||||||
while offset < file_size:
|
while offset < file_size:
|
||||||
# Update block size (if needed).
|
# Update block size (if needed).
|
||||||
|
@ -569,20 +637,18 @@ def usbHandleSendFileProperties(cmd_block):
|
||||||
|
|
||||||
# Update progress bar once per second.
|
# Update progress bar once per second.
|
||||||
pbar.update(float(chunk_size) / unit_divisor)
|
pbar.update(float(chunk_size) / unit_divisor)
|
||||||
pbar.refresh()
|
#pbar.refresh()
|
||||||
|
|
||||||
|
elapsed_time = round(time.time() - pbar.start)
|
||||||
|
g_Logger.info('File transfer successfully completed in %s!\n' % (tqdm.format_interval(elapsed_time)))
|
||||||
|
|
||||||
# Close progress bar
|
# Close progress bar
|
||||||
pbar.close()
|
pbar.close()
|
||||||
pbar._tk_window.destroy()
|
|
||||||
|
|
||||||
# Close file handle (if needed).
|
# Close file handle (if needed).
|
||||||
if g_nspTransferMode == False:
|
if g_nspTransferMode == False:
|
||||||
file.close()
|
file.close()
|
||||||
|
|
||||||
# I'd like to get this info from tqdm but it's not possible.
|
|
||||||
elapsed_time = round(time.time() - start_time)
|
|
||||||
g_Logger.info('File transfer successfully completed in %us!\n' % (elapsed_time))
|
|
||||||
|
|
||||||
return USB_STATUS_SUCCESS
|
return USB_STATUS_SUCCESS
|
||||||
|
|
||||||
def usbHandleSendNspHeader(cmd_block):
|
def usbHandleSendNspHeader(cmd_block):
|
||||||
|
@ -610,7 +676,7 @@ def usbHandleSendNspHeader(cmd_block):
|
||||||
g_nspFile.write(cmd_block)
|
g_nspFile.write(cmd_block)
|
||||||
g_nspFile.close()
|
g_nspFile.close()
|
||||||
|
|
||||||
g_Logger.debug('Successfully wrote 0x%X byte-long NSP header to "%s".' % (nsp_header_size, g_nspFilePath))
|
g_Logger.debug('Successfully wrote 0x%X byte-long NSP header to "%s".\n' % (nsp_header_size, g_nspFilePath))
|
||||||
|
|
||||||
# Disable NSP transfer mode.
|
# Disable NSP transfer mode.
|
||||||
utilsResetNspInfo()
|
utilsResetNspInfo()
|
||||||
|
@ -778,11 +844,8 @@ def uiScaleMeasure(measure):
|
||||||
def main():
|
def main():
|
||||||
global SCALE, g_tkRoot, g_tkCanvas, g_tkDirText, g_tkChooseDirButton, g_tkServerButton, g_tkTipMessage, g_tkScrolledTextLog
|
global SCALE, g_tkRoot, g_tkCanvas, g_tkDirText, g_tkChooseDirButton, g_tkServerButton, g_tkTipMessage, g_tkScrolledTextLog
|
||||||
|
|
||||||
# Configure logging mechanism.
|
# Disable warnings.
|
||||||
logging.basicConfig(level=logging.DEBUG)
|
warnings.filterwarnings("ignore")
|
||||||
"""if len(g_Logger.handlers) > 0:
|
|
||||||
log_stderr = g_Logger.handlers[0]
|
|
||||||
g_Logger.removeHandler(log_stderr)"""
|
|
||||||
|
|
||||||
# Get OS information.
|
# Get OS information.
|
||||||
os_type = platform.system()
|
os_type = platform.system()
|
||||||
|
@ -874,6 +937,12 @@ def main():
|
||||||
|
|
||||||
g_tkCanvas.create_text(uiScaleMeasure(5), uiScaleMeasure(WINDOW_HEIGHT - 10), text="Copyright (c) {}, {}".format(COPYRIGHT_YEAR, USB_DEV_MANUFACTURER), anchor=tk.W)
|
g_tkCanvas.create_text(uiScaleMeasure(5), uiScaleMeasure(WINDOW_HEIGHT - 10), text="Copyright (c) {}, {}".format(COPYRIGHT_YEAR, USB_DEV_MANUFACTURER), anchor=tk.W)
|
||||||
|
|
||||||
|
# Configure logging mechanism.
|
||||||
|
logging.basicConfig(level=logging.DEBUG)
|
||||||
|
if len(g_Logger.handlers) > 0:
|
||||||
|
log_stderr = g_Logger.handlers[0]
|
||||||
|
g_Logger.removeHandler(log_stderr)
|
||||||
|
|
||||||
# Initialize console g_Logger.
|
# Initialize console g_Logger.
|
||||||
console = LogConsole(g_tkScrolledTextLog)
|
console = LogConsole(g_tkScrolledTextLog)
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue