use chip id for all image checks

This commit is contained in:
andreas 2023-09-09 17:11:47 +02:00
parent c87c38fca4
commit f800893ac8
5 changed files with 99 additions and 82 deletions

View File

@ -268,10 +268,7 @@ def prebuild(env):
genereateUserTasks(os.path.join(outPath(), TASK_INCLUDE)) genereateUserTasks(os.path.join(outPath(), TASK_INCLUDE))
generateFile(os.path.join(basePath(),XDR_FILE),os.path.join(outPath(),XDR_INCLUDE),generateXdrMappings) generateFile(os.path.join(basePath(),XDR_FILE),os.path.join(outPath(),XDR_INCLUDE),generateXdrMappings)
version="dev"+datetime.now().strftime("%Y%m%d") version="dev"+datetime.now().strftime("%Y%m%d")
env.Append(CPPDEFINES=[ env.Append(CPPDEFINES=[('GWDEVVERSION',version)])
('GWDEVVERSION',version),
('PIO_ENV_BOARD',env.get('BOARD_MCU'))
])
def cleangenerated(source, target, env): def cleangenerated(source, target, env):
od=outPath() od=outPath()
@ -293,4 +290,3 @@ env.Append(
) )
#script does not run on clean yet - maybe in the future #script does not run on clean yet - maybe in the future
env.AddPostAction("clean",cleangenerated) env.AddPostAction("clean",cleangenerated)
#print(env.Dump())

View File

@ -72,7 +72,7 @@ def main():
tk.Label(frame,textvariable=self.fileInfo).grid(row=row,column=0,columnspan=2,sticky="ew") tk.Label(frame,textvariable=self.fileInfo).grid(row=row,column=0,columnspan=2,sticky="ew")
row+=1 row+=1
self.flashInfo=tk.StringVar() self.flashInfo=tk.StringVar()
self.flashInfo.set("Address 0x1000") self.flashInfo.set("Full Flash")
tk.Label(frame,textvariable=self.flashInfo).grid(row=row,column=0,columnspan=2,sticky='ew',pady=10) tk.Label(frame,textvariable=self.flashInfo).grid(row=row,column=0,columnspan=2,sticky='ew',pady=10)
row+=1 row+=1
btFrame=tk.Frame(frame) btFrame=tk.Frame(frame)
@ -96,7 +96,7 @@ def main():
def updateFlashInfo(self): def updateFlashInfo(self):
if self.mode.get() == 1: if self.mode.get() == 1:
#full #full
self.flashInfo.set("Address 0x1000") self.flashInfo.set("Full Flash")
else: else:
self.flashInfo.set("Erase(otadata): 0xe000...0xffff, Address 0x10000") self.flashInfo.set("Erase(otadata): 0xe000...0xffff, Address 0x10000")
def changeMode(self): def changeMode(self):
@ -141,50 +141,67 @@ def main():
self.interrupt=False self.interrupt=False
raise Exception("User cancel") raise Exception("User cancel")
FULLOFFSET=61440 UPDATE_ADDR = 0x10000
HDROFFSET = 288 HDROFFSET = 288
VERSIONOFFSET = 16 VERSIONOFFSET = 16
NAMEOFFSET = 48 NAMEOFFSET = 48
IDOFFSET=12 #2 byte chipid
MINSIZE = HDROFFSET + NAMEOFFSET + 32 MINSIZE = HDROFFSET + NAMEOFFSET + 32
CHECKBYTES = { CHECKBYTES = {
0: 0xe9, # image magic
288: 0x32, # app header magic 288: 0x32, # app header magic
289: 0x54, 289: 0x54,
290: 0xcd, 290: 0xcd,
291: 0xab 291: 0xab
} }
#flash addresses for full images based on chip id
FLASH_ADDR={
0: 0x1000,
9: 0
}
def getString(self,buffer, offset, len): def getString(self,buffer, offset, len):
return buffer[offset:offset + len].rstrip(b'\0').decode('utf-8') return buffer[offset:offset + len].rstrip(b'\0').decode('utf-8')
def getFirmwareInfo(self,ih,imageFile,offset): def getFirmwareInfo(self,filename,isFull):
buffer = ih.read(self.MINSIZE) with open(filename,"rb") as ih:
if len(buffer) != self.MINSIZE: buffer = ih.read(self.MINSIZE)
return self.setErr("invalid image file %s, to short"%imageFile) if len(buffer) != self.MINSIZE:
for k, v in self.CHECKBYTES.items(): return self.setErr("invalid image file %s, to short"%filename)
if buffer[k] != v: if buffer[0] != 0xe9:
return self.setErr("invalid magic at %d, expected %d got %d" 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])) % (k+offset, v, buffer[k]))
name = self.getString(buffer, self.HDROFFSET + self.NAMEOFFSET, 32) name = self.getString(buffer, self.HDROFFSET + self.NAMEOFFSET, 32)
version = self.getString(buffer, self.HDROFFSET + self.VERSIONOFFSET, 32) version = self.getString(buffer, self.HDROFFSET + self.VERSIONOFFSET, 32)
return {'error':False,'info':"%s:%s"%(name,version)} chipid= buffer[self.IDOFFSET]+256*buffer[self.IDOFFSET+1]
return {
'error':False,
'info':"%s:%s"%(name,version),
'chipid':chipid,
'flashbase':flashoffset if isFull else self.UPDATE_ADDR
}
def setErr(self,err): def setErr(self,err):
return {'error':True,'info':err} return {'error':True,'info':err}
def checkImageFile(self,filename,isFull): def checkImageFile(self,filename,isFull):
if not os.path.exists(filename): if not os.path.exists(filename):
return self.setErr("file %s not found"%filename) return self.setErr("file %s not found"%filename)
with open(filename,"rb") as fh: return self.getFirmwareInfo(filename,isFull)
offset=0
if isFull:
b=fh.read(1)
if len(b) != 1:
return self.setErr("unable to read header")
if b[0] != 0xe9:
return self.setErr("invalid magic in file, expected 0xe9 got 0x%02x"%b[0])
st=fh.seek(self.FULLOFFSET)
offset=self.FULLOFFSET
return self.getFirmwareInfo(fh,filename,offset)
def runCheck(self): def runCheck(self):
self.text_widget.delete("1.0", "end") self.text_widget.delete("1.0", "end")
@ -202,7 +219,7 @@ def main():
if info['error']: if info['error']:
print("ERROR: %s" % info['info']) print("ERROR: %s" % info['info'])
return return
return {'port':port,'isFull':isFull} return {'port':port,'isFull':isFull,'info':info}
def runEspTool(self,command): def runEspTool(self,command):
for b in self.actionButtons: for b in self.actionButtons:
@ -219,25 +236,36 @@ def main():
for b in self.actionButtons: for b in self.actionButtons:
b.configure(state=tk.NORMAL) b.configure(state=tk.NORMAL)
self.cancelButton.configure(state=tk.DISABLED) self.cancelButton.configure(state=tk.DISABLED)
def buttonCheck(self): def verifyChip(self):
param = self.runCheck() param = self.runCheck()
if not param: if not param:
print("check failed")
return return
print("Settings OK") imageChipId=param['info']['chipid']
command = ['--chip', 'ESP32', '--port', param['port'], 'chip_id'] chip=esptool.ESPLoader.detect_chip(param['port'])
self.runEspTool(command) 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 buttonCheck(self):
param = self.verifyChip()
def buttonFlash(self): def buttonFlash(self):
param=self.runCheck() param=self.verifyChip()
if not param: if not param:
return return
if param['isFull']: if param['isFull']:
command=['--chip','ESP32','--port',param['port'],'write_flash','0x1000',self.filename.get()] command=['--chip',param['chipname'],'--port',param['port'],'write_flash',str(param['info']['flashbase']),self.filename.get()]
self.runEspTool(command) self.runEspTool(command)
else: else:
command=['--chip','ESP32','--port',param['port'],'erase_region','0xe000','0x2000'] command=['--chip',param['chipname'],'--port',param['port'],'erase_region','0xe000','0x2000']
self.runEspTool(command) self.runEspTool(command)
command = ['--chip', 'ESP32', '--port', param['port'], 'write_flash', '0x10000', self.filename.get()] command = ['--chip', param['chipname'], '--port', param['port'], 'write_flash', str(param['info']['flashbase']), self.filename.get()]
self.runEspTool(command) self.runEspTool(command)

View File

@ -1564,14 +1564,14 @@ function uploadBin(ev){
.then(function (result) { .then(function (result) {
let currentType; let currentType;
let currentVersion; let currentVersion;
let chiptype; let chipid;
forEl('.status-version', function (el) { currentVersion = el.textContent }); forEl('.status-version', function (el) { currentVersion = el.textContent });
forEl('.status-fwtype', function (el) { currentType = el.textContent }); forEl('.status-fwtype', function (el) { currentType = el.textContent });
forEl('.status-chiptype', function (el) { chiptype = el.textContent }); forEl('.status-chipid', function (el) { chipid = el.textContent });
let confirmText = 'Ready to update firmware?\n'; let confirmText = 'Ready to update firmware?\n';
if (result.chip.match(/^@@/) && (result.chip.substr(2) != chiptype)){ if (result.chipId != chipid){
confirmText += "WARNING: the chiptype in the image ("+result.chip.substr(2); confirmText += "WARNING: the chipid in the image ("+result.chipId;
confirmText +=") does not match the current chip type ("+chiptype+").\n"; confirmText +=") does not match the current chip id ("+chipid+").\n";
} }
if (currentType != result.fwtype) { if (currentType != result.fwtype) {
confirmText += "WARNING: image has different type: " + result.fwtype + "\n"; confirmText += "WARNING: image has different type: " + result.fwtype + "\n";
@ -1649,8 +1649,8 @@ function uploadBin(ev){
let HDROFFSET=288; let HDROFFSET=288;
let VERSIONOFFSET=16; let VERSIONOFFSET=16;
let NAMEOFFSET=48; let NAMEOFFSET=48;
let CHIPOFFSET=NAMEOFFSET+64; let MINSIZE = HDROFFSET + NAMEOFFSET + 32;
let MINSIZE = HDROFFSET + CHIPOFFSET + 32; let CHIPIDOFFSET=12; //2 bytes chip id here
let imageCheckBytes={ let imageCheckBytes={
0: 0xe9, //image magic 0: 0xe9, //image magic
288: 0x32, //app header magic 288: 0x32, //app header magic
@ -1669,6 +1669,10 @@ function decodeFromBuffer(buffer,start,length){
start+length)); start+length));
return rt; return rt;
} }
function getChipId(buffer){
if (buffer.length < CHIPIDOFFSET+2) return -1;
return buffer[CHIPIDOFFSET]+256*buffer[CHIPIDOFFSET+1];
}
function checkImageFile(file){ function checkImageFile(file){
return new Promise(function(resolve,reject){ return new Promise(function(resolve,reject){
if (! file) reject("no file"); if (! file) reject("no file");
@ -1685,11 +1689,11 @@ function checkImageFile(file){
} }
let version=decodeFromBuffer(content,HDROFFSET+VERSIONOFFSET,32); let version=decodeFromBuffer(content,HDROFFSET+VERSIONOFFSET,32);
let fwtype=decodeFromBuffer(content,HDROFFSET+NAMEOFFSET,32); let fwtype=decodeFromBuffer(content,HDROFFSET+NAMEOFFSET,32);
let chip=decodeFromBuffer(content,HDROFFSET+CHIPOFFSET,32); let chipId=getChipId(content);
let rt={ let rt={
fwtype:fwtype, fwtype:fwtype,
version: version, version: version,
chip:chip chipId:chipId
}; };
resolve(rt); resolve(rt);
}); });
@ -1751,10 +1755,7 @@ window.addEventListener('load', function () {
checkImageFile(file) checkImageFile(file)
.then(function(res){ .then(function(res){
forEl('#imageProperties',function(iel){ forEl('#imageProperties',function(iel){
let txt=""; let txt="["+res.chipId+"] ";
if (res.chip.match(/^@@/)){
txt=res.chip.substr(2)+", "
}
txt+=res.fwtype+", "+res.version; txt+=res.fwtype+", "+res.version;
iel.textContent=txt; iel.textContent=txt;
iel.classList.remove("error"); iel.classList.remove("error");

View File

@ -10,8 +10,7 @@ import * as zip from "https://cdn.jsdelivr.net/npm/@zip.js/zip.js@2.7.29/+esm";
const HDROFFSET = 288; const HDROFFSET = 288;
const VERSIONOFFSET = 16; const VERSIONOFFSET = 16;
const NAMEOFFSET = 48; const NAMEOFFSET = 48;
const CHIPOFFSET=NAMEOFFSET+64; const MINSIZE = HDROFFSET + NAMEOFFSET + 32;
const MINSIZE = HDROFFSET + CHIPOFFSET + 32;
const CHIPIDOFFSET=12; //2 bytes chip id here const CHIPIDOFFSET=12; //2 bytes chip id here
const imageMagic=0xe9; //at byte 0 const imageMagic=0xe9; //at byte 0
const imageCheckBytes = { const imageCheckBytes = {
@ -22,6 +21,7 @@ import * as zip from "https://cdn.jsdelivr.net/npm/@zip.js/zip.js@2.7.29/+esm";
}; };
/** /**
* map of our known chip ids to flash starts for full images * map of our known chip ids to flash starts for full images
* 0 - esp32 - starts at 0x1000
* 9 - esp32s3 - starts at 0 * 9 - esp32s3 - starts at 0
*/ */
const FLASHSTART={ const FLASHSTART={
@ -47,8 +47,8 @@ import * as zip from "https://cdn.jsdelivr.net/npm/@zip.js/zip.js@2.7.29/+esm";
let prfx=isFull?"full":"update"; let prfx=isFull?"full":"update";
let startOffset=0; let startOffset=0;
let flashStart=UPDATE_START; let flashStart=UPDATE_START;
let chipId=getChipId(content);
if (isFull){ if (isFull){
let chipId=getChipId(content);
if (chipId < 0) throw new Error(prfx+"image: no valid chip id found"); if (chipId < 0) throw new Error(prfx+"image: no valid chip id found");
let flashStart=FLASHSTART[chipId]; let flashStart=FLASHSTART[chipId];
if (flashStart === undefined) throw new Error(prfx+"image: unknown chip id "+chipId); if (flashStart === undefined) throw new Error(prfx+"image: unknown chip id "+chipId);
@ -69,11 +69,10 @@ import * as zip from "https://cdn.jsdelivr.net/npm/@zip.js/zip.js@2.7.29/+esm";
} }
let version = decodeFromBuffer(content, startOffset+ HDROFFSET + VERSIONOFFSET, 32); let version = decodeFromBuffer(content, startOffset+ HDROFFSET + VERSIONOFFSET, 32);
let fwtype = decodeFromBuffer(content, startOffset+ HDROFFSET + NAMEOFFSET, 32); let fwtype = decodeFromBuffer(content, startOffset+ HDROFFSET + NAMEOFFSET, 32);
let chip=decodeFromBuffer(content,startOffset+HDROFFSET+CHIPOFFSET,32);
let rt = { let rt = {
fwtype: fwtype, fwtype: fwtype,
version: version, version: version,
chip:chip, chipId:chipId,
flashStart: flashStart flashStart: flashStart
}; };
return rt; return rt;
@ -133,22 +132,13 @@ import * as zip from "https://cdn.jsdelivr.net/npm/@zip.js/zip.js@2.7.29/+esm";
hFrame.textContent=''; hFrame.textContent='';
let h=addEl('h2',undefined,hFrame,`ESP32 Install ${info}`) let h=addEl('h2',undefined,hFrame,`ESP32 Install ${info}`)
} }
const checkChip= async (chipFamily,data,isFull)=>{ const checkChip= async (chipId,data,isFull)=>{
let info=checkImage(data,isFull); let info=checkImage(data,isFull);
if (info.chip && info.chip.match(/^@@/)){ if (info.chipId != chipId){
let chip=info.chip.substr(2); let res=confirm("different chip signatures - image("+chipId+"), chip ("+info.chipId+")\nUse this image any way?");
let compare=chipFamily.toLowerCase().replace(/[^a-z0-9]*/g,''); if (! res) throw new Error("user abort");
if (compare !== chip){
let res=confirm("different chip signatures - image("+chip+"), chip ("+compare+")\nUse this image any way?");
if (! res) throw new Error("user abort");
}
return;
} }
//for now only ESP32/ESP32-S3 return info;
if (chipFamily != "ESP32" && chipFamily != "ESP32-S3"){
throw new Error(`unexpected chip family ${chipFamily}, expected ESP32/ESP32-S3`);
}
return;
} }
const baudRates=[1200, const baudRates=[1200,
2400, 2400,
@ -339,7 +329,6 @@ import * as zip from "https://cdn.jsdelivr.net/npm/@zip.js/zip.js@2.7.29/+esm";
await espInstaller.runFlash( await espInstaller.runFlash(
true, true,
fullData, fullData,
vinfo.flashStart,
version, version,
checkChip checkChip
) )
@ -353,7 +342,6 @@ import * as zip from "https://cdn.jsdelivr.net/npm/@zip.js/zip.js@2.7.29/+esm";
await espInstaller.runFlash( await espInstaller.runFlash(
false, false,
updateData, updateData,
uinfo.flashStart,
version, version,
checkChip checkChip
) )

View File

@ -61,6 +61,7 @@ class ESPInstaller{
this.base=import.meta.url.replace(/[^/]*$/,"install.php"); this.base=import.meta.url.replace(/[^/]*$/,"install.php");
this.consoleDevice=undefined; this.consoleDevice=undefined;
this.consoleReader=undefined; this.consoleReader=undefined;
this.imageChipId=undefined;
} }
/** /**
* get an URL query parameter * get an URL query parameter
@ -133,6 +134,7 @@ class ESPInstaller{
this.espLoaderTerminal.writeLine(`chip: ${foundChip}`); this.espLoaderTerminal.writeLine(`chip: ${foundChip}`);
await this.esploader.flash_id(); await this.esploader.flash_id();
this.chipFamily = this.esploader.chip.CHIP_NAME; this.chipFamily = this.esploader.chip.CHIP_NAME;
this.imageChipId = this.esploader.chip.IMAGE_CHIP_ID;
this.espLoaderTerminal.writeLine(`chipFamily: ${this.chipFamily}`); this.espLoaderTerminal.writeLine(`chipFamily: ${this.chipFamily}`);
} catch (e) { } catch (e) {
this.disconnect(); this.disconnect();
@ -185,6 +187,10 @@ class ESPInstaller{
this.checkConnected(); this.checkConnected();
return this.chipFamily; return this.chipFamily;
} }
getChipId(){
this.checkConnected();
return this.imageChipId;
}
/** /**
* flass the device * flass the device
* @param {*} fileList : an array of entries {data:blob,address:number} * @param {*} fileList : an array of entries {data:blob,address:number}
@ -236,7 +242,7 @@ class ESPInstaller{
* @param {*} repo * @param {*} repo
* @param {*} version * @param {*} version
* @param {*} assetName * @param {*} assetName
* @param {*} checkChip will be called with the found chip and the data and the isFull flag * @param {*} checkChip will be called with the found chipId and the data and the isFull flag
* must return an info with the flashStart being set * must return an info with the flashStart being set
* @returns * @returns
*/ */
@ -247,7 +253,7 @@ class ESPInstaller{
if (!imageData || imageData.length == 0) { if (!imageData || imageData.length == 0) {
throw new Error(`no image data fetched`); throw new Error(`no image data fetched`);
} }
let info=await checkChip(this.getChipFamily(),imageData,isFull); let info=await checkChip(this.getChipId(),imageData,isFull);
let fileList = [ let fileList = [
{ data: imageData, address: info.flashAddress } { data: imageData, address: info.flashAddress }
]; ];
@ -267,20 +273,18 @@ class ESPInstaller{
/** /**
* directly run the flash * directly run the flash
* @param {*} isFull * @param {*} isFull
* @param {*} address
* @param {*} imageData the data to be flashed * @param {*} imageData the data to be flashed
* @param {*} version the info shown in the dialog * @param {*} version the info shown in the dialog
* @param {*} checkChip will be called with the found chip and the data * @param {*} checkChip will be called with the found chipId and the data
* must return an info with flashAddress
* @returns * @returns
*/ */
async runFlash(isFull,imageData,address,version,checkChip){ async runFlash(isFull,imageData,version,checkChip){
try { try {
await this.connect(); await this.connect();
if (checkChip) { let info= await checkChip(this.getChipId(),imageData,isFull); //just check
await checkChip(this.getChipFamily(),imageData,isFull); //just check
}
let fileList = [ let fileList = [
{ data: imageData, address: address } { data: imageData, address: info.flashAddress }
]; ];
let txt = isFull ? "baseImage (all data will be erased)" : "update"; let txt = isFull ? "baseImage (all data will be erased)" : "update";
if (!confirm(`ready to install ${version}\n${txt}`)) { if (!confirm(`ready to install ${version}\n${txt}`)) {