reorganize flash tool
This commit is contained in:
parent
d0018c6726
commit
f12d6267b4
|
@ -0,0 +1,124 @@
|
||||||
|
|
||||||
|
import flashtool.esptool as esptool
|
||||||
|
import os
|
||||||
|
from flashtool.version import VERSION
|
||||||
|
|
||||||
|
class Flasher():
|
||||||
|
def getVersion(self):
|
||||||
|
return ("Version %s, esptool %s"%(VERSION,str(esptool.__version__)))
|
||||||
|
|
||||||
|
UPDATE_ADDR = 0x10000
|
||||||
|
HDROFFSET = 288
|
||||||
|
VERSIONOFFSET = 16
|
||||||
|
NAMEOFFSET = 48
|
||||||
|
IDOFFSET=12 #2 byte chipid
|
||||||
|
MINSIZE = HDROFFSET + NAMEOFFSET + 32
|
||||||
|
CHECKBYTES = {
|
||||||
|
288: 0x32, # app header magic
|
||||||
|
289: 0x54,
|
||||||
|
290: 0xcd,
|
||||||
|
291: 0xab
|
||||||
|
}
|
||||||
|
#flash addresses for full images based on chip id
|
||||||
|
FLASH_ADDR={
|
||||||
|
0: 0x1000,
|
||||||
|
9: 0
|
||||||
|
}
|
||||||
|
def getString(self,buffer, offset, len):
|
||||||
|
return buffer[offset:offset + len].rstrip(b'\0').decode('utf-8')
|
||||||
|
def getFirmwareInfo(self,filename,isFull):
|
||||||
|
with open(filename,"rb") as ih:
|
||||||
|
buffer = ih.read(self.MINSIZE)
|
||||||
|
if len(buffer) != self.MINSIZE:
|
||||||
|
return self.setErr("invalid image file %s, to short"%filename)
|
||||||
|
if buffer[0] != 0xe9:
|
||||||
|
return self.setErr("invalid magic in file, expected 0xe9 got 0x%02x"%buffer[0])
|
||||||
|
chipid= buffer[self.IDOFFSET]+256*buffer[self.IDOFFSET+1]
|
||||||
|
flashoffset=self.FLASH_ADDR.get(chipid)
|
||||||
|
if flashoffset is None:
|
||||||
|
return self.setErr("unknown chip id in image %d",chipid);
|
||||||
|
if isFull:
|
||||||
|
offset=self.UPDATE_ADDR-flashoffset;
|
||||||
|
offset-=self.MINSIZE
|
||||||
|
ih.seek(offset,os.SEEK_CUR)
|
||||||
|
buffer=ih.read(self.MINSIZE)
|
||||||
|
if len(buffer) != self.MINSIZE:
|
||||||
|
return self.setErr("invalid image file %s, to short"%filename)
|
||||||
|
if buffer[0] != 0xe9:
|
||||||
|
return self.setErr("invalid magic in file, expected 0xe9 got 0x%02x"%buffer[0])
|
||||||
|
for k, v in self.CHECKBYTES.items():
|
||||||
|
if buffer[k] != v:
|
||||||
|
return self.setErr("invalid magic at %d, expected %d got %d"
|
||||||
|
% (k+offset, v, buffer[k]))
|
||||||
|
name = self.getString(buffer, self.HDROFFSET + self.NAMEOFFSET, 32)
|
||||||
|
version = self.getString(buffer, self.HDROFFSET + self.VERSIONOFFSET, 32)
|
||||||
|
chipid= buffer[self.IDOFFSET]+256*buffer[self.IDOFFSET+1]
|
||||||
|
flashoffset=flashoffset if isFull else self.UPDATE_ADDR
|
||||||
|
return {
|
||||||
|
'error':False,
|
||||||
|
'info':"%s:%s"%(name,version),
|
||||||
|
'chipid':chipid,
|
||||||
|
'flashbase':flashoffset
|
||||||
|
}
|
||||||
|
def setErr(self,err):
|
||||||
|
return {'error':True,'info':err}
|
||||||
|
def checkImageFile(self,filename,isFull):
|
||||||
|
if not os.path.exists(filename):
|
||||||
|
return self.setErr("file %s not found"%filename)
|
||||||
|
return self.getFirmwareInfo(filename,isFull)
|
||||||
|
|
||||||
|
def checkSettings(self,port,fileName,isFull):
|
||||||
|
if port is None:
|
||||||
|
print("ERROR: no com port selected")
|
||||||
|
return
|
||||||
|
if fileName is None or fileName == '':
|
||||||
|
print("ERROR: no filename selected")
|
||||||
|
return
|
||||||
|
info = self.checkImageFile(fileName, isFull)
|
||||||
|
if info['error']:
|
||||||
|
print("ERROR: %s" % info['info'])
|
||||||
|
return
|
||||||
|
return {'fileName': fileName,'port':port,'isFull':isFull,'info':info}
|
||||||
|
def runEspTool(self,command):
|
||||||
|
print("run esptool: %s" % " ".join(command))
|
||||||
|
try:
|
||||||
|
esptool.main(command)
|
||||||
|
print("esptool done")
|
||||||
|
return True
|
||||||
|
except Exception as e:
|
||||||
|
print("Exception in esptool %s" % e)
|
||||||
|
def verifyChip(self,param):
|
||||||
|
if not param:
|
||||||
|
print("check failed")
|
||||||
|
return
|
||||||
|
imageChipId=param['info']['chipid']
|
||||||
|
chip=esptool.ESPLoader.detect_chip(param['port'])
|
||||||
|
print("Detected chip %s, id=%d"%(chip.CHIP_NAME,chip.IMAGE_CHIP_ID))
|
||||||
|
if (chip.IMAGE_CHIP_ID != imageChipId):
|
||||||
|
print("##Error: chip id in image %d does not match detected chip"%imageChipId)
|
||||||
|
return
|
||||||
|
print("Checks OK")
|
||||||
|
param['chipname']=chip.CHIP_NAME
|
||||||
|
return param
|
||||||
|
def runCheck(self,port,fileName,isFull):
|
||||||
|
param = self.checkSettings(port,fileName,isFull)
|
||||||
|
if not param:
|
||||||
|
return
|
||||||
|
print("Settings OK")
|
||||||
|
param=self.verifyChip(param)
|
||||||
|
if not param:
|
||||||
|
print("Check Failed")
|
||||||
|
return
|
||||||
|
print("flashbase=0x%x"%param['info']['flashbase'])
|
||||||
|
return param
|
||||||
|
def runFlash(self,param):
|
||||||
|
if not param:
|
||||||
|
return
|
||||||
|
if param['isFull']:
|
||||||
|
command=['--chip',param['chipname'],'--port',param['port'],'write_flash',str(param['info']['flashbase']),param['fileName']]
|
||||||
|
self.runEspTool(command)
|
||||||
|
else:
|
||||||
|
command=['--chip',param['chipname'],'--port',param['port'],'erase_region','0xe000','0x2000']
|
||||||
|
self.runEspTool(command)
|
||||||
|
command = ['--chip', param['chipname'], '--port', param['port'], 'write_flash', str(param['info']['flashbase']), param['fileName']]
|
||||||
|
self.runEspTool(command)
|
|
@ -1,6 +1,38 @@
|
||||||
#! /usr/bin/env python3
|
#! /usr/bin/env python3
|
||||||
|
import builtins
|
||||||
import subprocess
|
import subprocess
|
||||||
import sys
|
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 fullname == self.pkg:
|
||||||
|
if self.debug:
|
||||||
|
print("F:matching %"%fullname)
|
||||||
|
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:
|
try:
|
||||||
import serial
|
import serial
|
||||||
|
@ -16,130 +48,8 @@ import tkinter.font as tkFont
|
||||||
import os
|
import os
|
||||||
import serial.tools.list_ports
|
import serial.tools.list_ports
|
||||||
from tkinter import filedialog as FileDialog
|
from tkinter import filedialog as FileDialog
|
||||||
|
from flashtool.flasher import Flasher
|
||||||
|
|
||||||
import builtins
|
|
||||||
import esptool
|
|
||||||
|
|
||||||
VERSION="Version 2.0"
|
|
||||||
class Flasher():
|
|
||||||
def getVersion(self):
|
|
||||||
return ("Version %s, esptool %s"%(VERSION,str(esptool.__version__)))
|
|
||||||
|
|
||||||
UPDATE_ADDR = 0x10000
|
|
||||||
HDROFFSET = 288
|
|
||||||
VERSIONOFFSET = 16
|
|
||||||
NAMEOFFSET = 48
|
|
||||||
IDOFFSET=12 #2 byte chipid
|
|
||||||
MINSIZE = HDROFFSET + NAMEOFFSET + 32
|
|
||||||
CHECKBYTES = {
|
|
||||||
288: 0x32, # app header magic
|
|
||||||
289: 0x54,
|
|
||||||
290: 0xcd,
|
|
||||||
291: 0xab
|
|
||||||
}
|
|
||||||
#flash addresses for full images based on chip id
|
|
||||||
FLASH_ADDR={
|
|
||||||
0: 0x1000,
|
|
||||||
9: 0
|
|
||||||
}
|
|
||||||
def getString(self,buffer, offset, len):
|
|
||||||
return buffer[offset:offset + len].rstrip(b'\0').decode('utf-8')
|
|
||||||
def getFirmwareInfo(self,filename,isFull):
|
|
||||||
with open(filename,"rb") as ih:
|
|
||||||
buffer = ih.read(self.MINSIZE)
|
|
||||||
if len(buffer) != self.MINSIZE:
|
|
||||||
return self.setErr("invalid image file %s, to short"%filename)
|
|
||||||
if buffer[0] != 0xe9:
|
|
||||||
return self.setErr("invalid magic in file, expected 0xe9 got 0x%02x"%buffer[0])
|
|
||||||
chipid= buffer[self.IDOFFSET]+256*buffer[self.IDOFFSET+1]
|
|
||||||
flashoffset=self.FLASH_ADDR.get(chipid)
|
|
||||||
if flashoffset is None:
|
|
||||||
return self.setErr("unknown chip id in image %d",chipid);
|
|
||||||
if isFull:
|
|
||||||
offset=self.UPDATE_ADDR-flashoffset;
|
|
||||||
offset-=self.MINSIZE
|
|
||||||
ih.seek(offset,os.SEEK_CUR)
|
|
||||||
buffer=ih.read(self.MINSIZE)
|
|
||||||
if len(buffer) != self.MINSIZE:
|
|
||||||
return self.setErr("invalid image file %s, to short"%filename)
|
|
||||||
if buffer[0] != 0xe9:
|
|
||||||
return self.setErr("invalid magic in file, expected 0xe9 got 0x%02x"%buffer[0])
|
|
||||||
for k, v in self.CHECKBYTES.items():
|
|
||||||
if buffer[k] != v:
|
|
||||||
return self.setErr("invalid magic at %d, expected %d got %d"
|
|
||||||
% (k+offset, v, buffer[k]))
|
|
||||||
name = self.getString(buffer, self.HDROFFSET + self.NAMEOFFSET, 32)
|
|
||||||
version = self.getString(buffer, self.HDROFFSET + self.VERSIONOFFSET, 32)
|
|
||||||
chipid= buffer[self.IDOFFSET]+256*buffer[self.IDOFFSET+1]
|
|
||||||
flashoffset=flashoffset if isFull else self.UPDATE_ADDR
|
|
||||||
return {
|
|
||||||
'error':False,
|
|
||||||
'info':"%s:%s"%(name,version),
|
|
||||||
'chipid':chipid,
|
|
||||||
'flashbase':flashoffset
|
|
||||||
}
|
|
||||||
def setErr(self,err):
|
|
||||||
return {'error':True,'info':err}
|
|
||||||
def checkImageFile(self,filename,isFull):
|
|
||||||
if not os.path.exists(filename):
|
|
||||||
return self.setErr("file %s not found"%filename)
|
|
||||||
return self.getFirmwareInfo(filename,isFull)
|
|
||||||
|
|
||||||
def checkSettings(self,port,fileName,isFull):
|
|
||||||
if port is None:
|
|
||||||
print("ERROR: no com port selected")
|
|
||||||
return
|
|
||||||
if fileName is None or fileName == '':
|
|
||||||
print("ERROR: no filename selected")
|
|
||||||
return
|
|
||||||
info = self.checkImageFile(fileName, isFull)
|
|
||||||
if info['error']:
|
|
||||||
print("ERROR: %s" % info['info'])
|
|
||||||
return
|
|
||||||
return {'fileName': fileName,'port':port,'isFull':isFull,'info':info}
|
|
||||||
def runEspTool(self,command):
|
|
||||||
print("run esptool: %s" % " ".join(command))
|
|
||||||
try:
|
|
||||||
esptool.main(command)
|
|
||||||
print("esptool done")
|
|
||||||
return True
|
|
||||||
except Exception as e:
|
|
||||||
print("Exception in esptool %s" % e)
|
|
||||||
def verifyChip(self,param):
|
|
||||||
if not param:
|
|
||||||
print("check failed")
|
|
||||||
return
|
|
||||||
imageChipId=param['info']['chipid']
|
|
||||||
chip=esptool.ESPLoader.detect_chip(param['port'])
|
|
||||||
print("Detected chip %s, id=%d"%(chip.CHIP_NAME,chip.IMAGE_CHIP_ID))
|
|
||||||
if (chip.IMAGE_CHIP_ID != imageChipId):
|
|
||||||
print("##Error: chip id in image %d does not match detected chip"%imageChipId)
|
|
||||||
return
|
|
||||||
print("Checks OK")
|
|
||||||
param['chipname']=chip.CHIP_NAME
|
|
||||||
return param
|
|
||||||
def runCheck(self,port,fileName,isFull):
|
|
||||||
param = self.checkSettings(port,fileName,isFull)
|
|
||||||
if not param:
|
|
||||||
return
|
|
||||||
print("Settings OK")
|
|
||||||
param=self.verifyChip(param)
|
|
||||||
if not param:
|
|
||||||
print("Check Failed")
|
|
||||||
return
|
|
||||||
print("flashbase=0x%x"%param['info']['flashbase'])
|
|
||||||
return param
|
|
||||||
def runFlash(self,param):
|
|
||||||
if not param:
|
|
||||||
return
|
|
||||||
if param['isFull']:
|
|
||||||
command=['--chip',param['chipname'],'--port',param['port'],'write_flash',str(param['info']['flashbase']),param['fileName']]
|
|
||||||
self.runEspTool(command)
|
|
||||||
else:
|
|
||||||
command=['--chip',param['chipname'],'--port',param['port'],'erase_region','0xe000','0x2000']
|
|
||||||
self.runEspTool(command)
|
|
||||||
command = ['--chip', param['chipname'], '--port', param['port'], 'write_flash', str(param['info']['flashbase']), param['fileName']]
|
|
||||||
self.runEspTool(command)
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
VERSION="2.1"
|
Loading…
Reference in New Issue