esp32-nmea2000-obp60/tools/flashtool/flashtool.py

224 lines
7.9 KiB
Python
Executable File

#! /usr/bin/env python3
import builtins
import subprocess
import sys
import os
import importlib.abc
import importlib.util
import types
'''
Inject a base package for our current directory
'''
class MyLoader(importlib.abc.InspectLoader):
def is_package(self, fullname: str) -> bool:
return True
def get_source(self, fullname: str):
return None
def get_code(self, fullname: str):
return ""
class MyFinder(importlib.abc.MetaPathFinder):
def __init__(self,baspkg,basedir=os.path.dirname(__file__),debug=False):
self.pkg=baspkg
self.dir=basedir
self.debug=debug
def find_spec(self,fullname, path, target=None):
if self.debug:
print("F:fullname=%s"%fullname)
if fullname == self.pkg:
if self.debug:
print("F:matching %s(%s)"%(fullname,self.dir))
spec=importlib.util.spec_from_file_location(fullname, self.dir,loader=MyLoader(), submodule_search_locations=[self.dir])
if self.debug:
print("F:injecting:",spec)
return spec
sys.meta_path.insert(0,MyFinder('flashtool'))
try:
import serial
except ImportError:
subprocess.check_call([sys.executable, "-m", "pip", "install", 'pyserial'])
finally:
import serial
import tkinter as tk
from tkinter import ttk
import tkinter.font as tkFont
import os
import serial.tools.list_ports
from tkinter import filedialog as FileDialog
try:
from flasher import Flasher
except:
from flashtool.flasher import Flasher
def main():
oldprint=builtins.print
def print(*args, **kwargs):
app.addText(*args,**kwargs)
builtins.print=print
import esptool
class App:
def __init__(self, root):
self.flasher=Flasher()
root.title("ESP32 NMEA2000 Flash Tool")
root.geometry("800x600")
root.resizable(width=True, height=True)
root.configure(background='lightgrey')
root.columnconfigure(0, weight=1)
root.rowconfigure(0, weight=1)
frame=tk.Frame(root)
row=0
frame.grid(row=0,column=0,sticky='news',padx=10,pady=5)
DUMMY = "prevent to handled as virus"
#frame.configure(background='lightblue')
frame.columnconfigure(0,weight=1)
frame.columnconfigure(1, weight=3)
tk.Label(frame,text="ESP32 NMEA2000 Flash Tool").grid(row=row,column=0,columnspan=2,sticky='ew')
row+=1
tk.Label(frame, text=self.flasher.getVersion()).grid(row=row,column=0,columnspan=2,sticky="ew",pady=10)
row+=1
self.mode=tk.IntVar()
self.mode.set(1)
rdFrame=tk.Frame(frame)
rdFrame.grid(row=row,column=1,sticky="ew",pady=20)
tk.Radiobutton(rdFrame,text="Initial Flash",value=1,variable=self.mode,command=self.changeMode).grid(row=0,column=0)
tk.Radiobutton(rdFrame, text="Update Flash", value=2, variable=self.mode,command=self.changeMode).grid(row=0,column=1)
row+=1
tk.Label(frame, text="Com Port").grid(row=row,column=0,sticky='ew')
ttk.Style().configure("TCombobox",padding=8,arrowsize=28)
ttk.Style().configure("TEntry", padding=8)
self.port=ttk.Combobox(frame)
self.port.grid(row=row,column=1,sticky="ew",pady=5)
row+=1
tk.Label(frame,text="Select Firmware").grid(row=row,column=0,sticky='ew')
self.filename=tk.StringVar()
fn=ttk.Entry(frame,textvariable=self.filename)
fn.grid(row=row,column=1,sticky='ew',pady=5)
fn.bind("<1>",self.fileDialog)
row+=1
self.fileInfo=tk.StringVar()
tk.Label(frame,textvariable=self.fileInfo).grid(row=row,column=0,columnspan=2,sticky="ew")
row+=1
self.flashInfo=tk.StringVar()
self.flashInfo.set("Full Flash")
tk.Label(frame,textvariable=self.flashInfo).grid(row=row,column=0,columnspan=2,sticky='ew',pady=10)
row+=1
btFrame=tk.Frame(frame)
btFrame.grid(row=row,column=0,columnspan=2,pady=15)
self.actionButtons=[]
bt=tk.Button(btFrame,text="Check",command=self.buttonCheck)
bt.grid(row=0,column=0)
self.actionButtons.append(bt)
bt=tk.Button(btFrame, text="Flash", command=self.buttonFlash)
bt.grid(row=0, column=1)
self.actionButtons.append(bt)
self.cancelButton=tk.Button(btFrame,text="Cancel",state=tk.DISABLED,command=self.buttonCancel)
self.cancelButton.grid(row=0,column=2)
row+=1
self.text_widget = tk.Text(frame)
frame.rowconfigure(row,weight=1)
self.text_widget.grid(row=row,column=0,columnspan=2,sticky='news')
self.readDevices()
self.interrupt=False
def updateFlashInfo(self):
if self.mode.get() == 1:
#full
self.flashInfo.set("Full Flash")
else:
self.flashInfo.set("Erase(otadata): 0xe000...0xffff, Address 0x10000")
def changeMode(self):
m=self.mode.get()
self.updateFlashInfo()
self.filename.set('')
self.fileInfo.set('')
def fileDialog(self,ev):
fn=FileDialog.askopenfilename()
if fn:
self.filename.set(fn)
info=self.flasher.checkImageFile(fn,self.mode.get() == 1)
if info['error']:
self.fileInfo.set("***ERROR: %s"%info['info'])
else:
self.fileInfo.set(info['info'])
def readDevices(self):
self.serialDevices=[]
names=[]
for dev in serial.tools.list_ports.comports(False):
self.serialDevices.append(dev.device)
if dev.description != 'n/a':
label=dev.description+"("+dev.device+")"
else:
label=dev.name+"("+dev.device+")"
names.append(label)
self.port.configure(values=names)
def addText(self,*args,**kwargs):
first=True
for k in args:
self.text_widget.insert(tk.END,k)
if not first:
self.text_widget.insert(tk.END, ',')
first=False
if kwargs.get('end') is None:
self.text_widget.insert(tk.END,"\n")
else:
self.text_widget.insert(tk.END,kwargs.get('end'))
self.text_widget.see('end')
root.update()
if self.interrupt:
self.interrupt=False
raise Exception("User cancel")
def runCheck(self):
self.text_widget.delete("1.0", "end")
idx = self.port.current()
isFull = self.mode.get() == 1
if idx < 0:
self.addText("ERROR: no com port selected")
return
port = self.serialDevices[idx]
fn = self.filename.get()
param = self.flasher.runCheck(port,fn,isFull)
return param
def runFlash(self,param):
for b in self.actionButtons:
b.configure(state=tk.DISABLED)
self.cancelButton.configure(state=tk.NORMAL)
root.update()
root.update_idletasks()
self.flasher.runFlash(param)
for b in self.actionButtons:
b.configure(state=tk.NORMAL)
self.cancelButton.configure(state=tk.DISABLED)
def buttonCheck(self):
param = self.runCheck()
def buttonFlash(self):
param=self.runCheck()
if not param:
return
self.runFlash(param)
def buttonCancel(self):
self.interrupt=True
root = tk.Tk()
app = App(root)
root.mainloop()
if __name__ == "__main__":
main()