reorganize flash tool

This commit is contained in:
andreas 2023-11-05 17:55:06 +01:00
parent d0018c6726
commit f12d6267b4
3 changed files with 158 additions and 123 deletions

124
tools/flashtool/flasher.py Normal file
View File

@ -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)

View File

@ -1,6 +1,38 @@
#! /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 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:
import serial
@ -16,130 +48,8 @@ import tkinter.font as tkFont
import os
import serial.tools.list_ports
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():

View File

@ -0,0 +1 @@
VERSION="2.1"