use chip id for all image checks
This commit is contained in:
parent
c87c38fca4
commit
f800893ac8
|
@ -268,10 +268,7 @@ def prebuild(env):
|
|||
genereateUserTasks(os.path.join(outPath(), TASK_INCLUDE))
|
||||
generateFile(os.path.join(basePath(),XDR_FILE),os.path.join(outPath(),XDR_INCLUDE),generateXdrMappings)
|
||||
version="dev"+datetime.now().strftime("%Y%m%d")
|
||||
env.Append(CPPDEFINES=[
|
||||
('GWDEVVERSION',version),
|
||||
('PIO_ENV_BOARD',env.get('BOARD_MCU'))
|
||||
])
|
||||
env.Append(CPPDEFINES=[('GWDEVVERSION',version)])
|
||||
|
||||
def cleangenerated(source, target, env):
|
||||
od=outPath()
|
||||
|
@ -293,4 +290,3 @@ env.Append(
|
|||
)
|
||||
#script does not run on clean yet - maybe in the future
|
||||
env.AddPostAction("clean",cleangenerated)
|
||||
#print(env.Dump())
|
||||
|
|
|
@ -72,7 +72,7 @@ def main():
|
|||
tk.Label(frame,textvariable=self.fileInfo).grid(row=row,column=0,columnspan=2,sticky="ew")
|
||||
row+=1
|
||||
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)
|
||||
row+=1
|
||||
btFrame=tk.Frame(frame)
|
||||
|
@ -96,7 +96,7 @@ def main():
|
|||
def updateFlashInfo(self):
|
||||
if self.mode.get() == 1:
|
||||
#full
|
||||
self.flashInfo.set("Address 0x1000")
|
||||
self.flashInfo.set("Full Flash")
|
||||
else:
|
||||
self.flashInfo.set("Erase(otadata): 0xe000...0xffff, Address 0x10000")
|
||||
def changeMode(self):
|
||||
|
@ -141,50 +141,67 @@ def main():
|
|||
self.interrupt=False
|
||||
raise Exception("User cancel")
|
||||
|
||||
FULLOFFSET=61440
|
||||
UPDATE_ADDR = 0x10000
|
||||
HDROFFSET = 288
|
||||
VERSIONOFFSET = 16
|
||||
NAMEOFFSET = 48
|
||||
IDOFFSET=12 #2 byte chipid
|
||||
MINSIZE = HDROFFSET + NAMEOFFSET + 32
|
||||
CHECKBYTES = {
|
||||
0: 0xe9, # image magic
|
||||
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,ih,imageFile,offset):
|
||||
buffer = ih.read(self.MINSIZE)
|
||||
if len(buffer) != self.MINSIZE:
|
||||
return self.setErr("invalid image file %s, to short"%imageFile)
|
||||
for k, v in self.CHECKBYTES.items():
|
||||
if buffer[k] != v:
|
||||
return self.setErr("invalid magic at %d, expected %d got %d"
|
||||
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)
|
||||
return {'error':False,'info':"%s:%s"%(name,version)}
|
||||
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]
|
||||
return {
|
||||
'error':False,
|
||||
'info':"%s:%s"%(name,version),
|
||||
'chipid':chipid,
|
||||
'flashbase':flashoffset if isFull else self.UPDATE_ADDR
|
||||
}
|
||||
|
||||
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)
|
||||
with open(filename,"rb") as fh:
|
||||
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)
|
||||
return self.getFirmwareInfo(filename,isFull)
|
||||
|
||||
def runCheck(self):
|
||||
self.text_widget.delete("1.0", "end")
|
||||
|
@ -202,7 +219,7 @@ def main():
|
|||
if info['error']:
|
||||
print("ERROR: %s" % info['info'])
|
||||
return
|
||||
return {'port':port,'isFull':isFull}
|
||||
return {'port':port,'isFull':isFull,'info':info}
|
||||
|
||||
def runEspTool(self,command):
|
||||
for b in self.actionButtons:
|
||||
|
@ -219,25 +236,36 @@ def main():
|
|||
for b in self.actionButtons:
|
||||
b.configure(state=tk.NORMAL)
|
||||
self.cancelButton.configure(state=tk.DISABLED)
|
||||
def buttonCheck(self):
|
||||
def verifyChip(self):
|
||||
param = self.runCheck()
|
||||
if not param:
|
||||
print("check failed")
|
||||
return
|
||||
print("Settings OK")
|
||||
command = ['--chip', 'ESP32', '--port', param['port'], 'chip_id']
|
||||
self.runEspTool(command)
|
||||
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 buttonCheck(self):
|
||||
param = self.verifyChip()
|
||||
|
||||
|
||||
|
||||
def buttonFlash(self):
|
||||
param=self.runCheck()
|
||||
param=self.verifyChip()
|
||||
if not param:
|
||||
return
|
||||
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)
|
||||
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)
|
||||
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)
|
||||
|
||||
|
||||
|
|
27
web/index.js
27
web/index.js
|
@ -1564,14 +1564,14 @@ function uploadBin(ev){
|
|||
.then(function (result) {
|
||||
let currentType;
|
||||
let currentVersion;
|
||||
let chiptype;
|
||||
let chipid;
|
||||
forEl('.status-version', function (el) { currentVersion = 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';
|
||||
if (result.chip.match(/^@@/) && (result.chip.substr(2) != chiptype)){
|
||||
confirmText += "WARNING: the chiptype in the image ("+result.chip.substr(2);
|
||||
confirmText +=") does not match the current chip type ("+chiptype+").\n";
|
||||
if (result.chipId != chipid){
|
||||
confirmText += "WARNING: the chipid in the image ("+result.chipId;
|
||||
confirmText +=") does not match the current chip id ("+chipid+").\n";
|
||||
}
|
||||
if (currentType != result.fwtype) {
|
||||
confirmText += "WARNING: image has different type: " + result.fwtype + "\n";
|
||||
|
@ -1649,8 +1649,8 @@ function uploadBin(ev){
|
|||
let HDROFFSET=288;
|
||||
let VERSIONOFFSET=16;
|
||||
let NAMEOFFSET=48;
|
||||
let CHIPOFFSET=NAMEOFFSET+64;
|
||||
let MINSIZE = HDROFFSET + CHIPOFFSET + 32;
|
||||
let MINSIZE = HDROFFSET + NAMEOFFSET + 32;
|
||||
let CHIPIDOFFSET=12; //2 bytes chip id here
|
||||
let imageCheckBytes={
|
||||
0: 0xe9, //image magic
|
||||
288: 0x32, //app header magic
|
||||
|
@ -1669,6 +1669,10 @@ function decodeFromBuffer(buffer,start,length){
|
|||
start+length));
|
||||
return rt;
|
||||
}
|
||||
function getChipId(buffer){
|
||||
if (buffer.length < CHIPIDOFFSET+2) return -1;
|
||||
return buffer[CHIPIDOFFSET]+256*buffer[CHIPIDOFFSET+1];
|
||||
}
|
||||
function checkImageFile(file){
|
||||
return new Promise(function(resolve,reject){
|
||||
if (! file) reject("no file");
|
||||
|
@ -1685,11 +1689,11 @@ function checkImageFile(file){
|
|||
}
|
||||
let version=decodeFromBuffer(content,HDROFFSET+VERSIONOFFSET,32);
|
||||
let fwtype=decodeFromBuffer(content,HDROFFSET+NAMEOFFSET,32);
|
||||
let chip=decodeFromBuffer(content,HDROFFSET+CHIPOFFSET,32);
|
||||
let chipId=getChipId(content);
|
||||
let rt={
|
||||
fwtype:fwtype,
|
||||
version: version,
|
||||
chip:chip
|
||||
chipId:chipId
|
||||
};
|
||||
resolve(rt);
|
||||
});
|
||||
|
@ -1751,10 +1755,7 @@ window.addEventListener('load', function () {
|
|||
checkImageFile(file)
|
||||
.then(function(res){
|
||||
forEl('#imageProperties',function(iel){
|
||||
let txt="";
|
||||
if (res.chip.match(/^@@/)){
|
||||
txt=res.chip.substr(2)+", "
|
||||
}
|
||||
let txt="["+res.chipId+"] ";
|
||||
txt+=res.fwtype+", "+res.version;
|
||||
iel.textContent=txt;
|
||||
iel.classList.remove("error");
|
||||
|
|
|
@ -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 VERSIONOFFSET = 16;
|
||||
const NAMEOFFSET = 48;
|
||||
const CHIPOFFSET=NAMEOFFSET+64;
|
||||
const MINSIZE = HDROFFSET + CHIPOFFSET + 32;
|
||||
const MINSIZE = HDROFFSET + NAMEOFFSET + 32;
|
||||
const CHIPIDOFFSET=12; //2 bytes chip id here
|
||||
const imageMagic=0xe9; //at byte 0
|
||||
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
|
||||
* 0 - esp32 - starts at 0x1000
|
||||
* 9 - esp32s3 - starts at 0
|
||||
*/
|
||||
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 startOffset=0;
|
||||
let flashStart=UPDATE_START;
|
||||
let chipId=getChipId(content);
|
||||
if (isFull){
|
||||
let chipId=getChipId(content);
|
||||
if (chipId < 0) throw new Error(prfx+"image: no valid chip id found");
|
||||
let flashStart=FLASHSTART[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 fwtype = decodeFromBuffer(content, startOffset+ HDROFFSET + NAMEOFFSET, 32);
|
||||
let chip=decodeFromBuffer(content,startOffset+HDROFFSET+CHIPOFFSET,32);
|
||||
let rt = {
|
||||
fwtype: fwtype,
|
||||
version: version,
|
||||
chip:chip,
|
||||
chipId:chipId,
|
||||
flashStart: flashStart
|
||||
};
|
||||
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='';
|
||||
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);
|
||||
if (info.chip && info.chip.match(/^@@/)){
|
||||
let chip=info.chip.substr(2);
|
||||
let compare=chipFamily.toLowerCase().replace(/[^a-z0-9]*/g,'');
|
||||
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;
|
||||
if (info.chipId != chipId){
|
||||
let res=confirm("different chip signatures - image("+chipId+"), chip ("+info.chipId+")\nUse this image any way?");
|
||||
if (! res) throw new Error("user abort");
|
||||
}
|
||||
//for now only ESP32/ESP32-S3
|
||||
if (chipFamily != "ESP32" && chipFamily != "ESP32-S3"){
|
||||
throw new Error(`unexpected chip family ${chipFamily}, expected ESP32/ESP32-S3`);
|
||||
}
|
||||
return;
|
||||
return info;
|
||||
}
|
||||
const baudRates=[1200,
|
||||
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(
|
||||
true,
|
||||
fullData,
|
||||
vinfo.flashStart,
|
||||
version,
|
||||
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(
|
||||
false,
|
||||
updateData,
|
||||
uinfo.flashStart,
|
||||
version,
|
||||
checkChip
|
||||
)
|
||||
|
|
|
@ -61,6 +61,7 @@ class ESPInstaller{
|
|||
this.base=import.meta.url.replace(/[^/]*$/,"install.php");
|
||||
this.consoleDevice=undefined;
|
||||
this.consoleReader=undefined;
|
||||
this.imageChipId=undefined;
|
||||
}
|
||||
/**
|
||||
* get an URL query parameter
|
||||
|
@ -133,6 +134,7 @@ class ESPInstaller{
|
|||
this.espLoaderTerminal.writeLine(`chip: ${foundChip}`);
|
||||
await this.esploader.flash_id();
|
||||
this.chipFamily = this.esploader.chip.CHIP_NAME;
|
||||
this.imageChipId = this.esploader.chip.IMAGE_CHIP_ID;
|
||||
this.espLoaderTerminal.writeLine(`chipFamily: ${this.chipFamily}`);
|
||||
} catch (e) {
|
||||
this.disconnect();
|
||||
|
@ -185,6 +187,10 @@ class ESPInstaller{
|
|||
this.checkConnected();
|
||||
return this.chipFamily;
|
||||
}
|
||||
getChipId(){
|
||||
this.checkConnected();
|
||||
return this.imageChipId;
|
||||
}
|
||||
/**
|
||||
* flass the device
|
||||
* @param {*} fileList : an array of entries {data:blob,address:number}
|
||||
|
@ -236,7 +242,7 @@ class ESPInstaller{
|
|||
* @param {*} repo
|
||||
* @param {*} version
|
||||
* @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
|
||||
* @returns
|
||||
*/
|
||||
|
@ -247,7 +253,7 @@ class ESPInstaller{
|
|||
if (!imageData || imageData.length == 0) {
|
||||
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 = [
|
||||
{ data: imageData, address: info.flashAddress }
|
||||
];
|
||||
|
@ -267,20 +273,18 @@ class ESPInstaller{
|
|||
/**
|
||||
* directly run the flash
|
||||
* @param {*} isFull
|
||||
* @param {*} address
|
||||
* @param {*} imageData the data to be flashed
|
||||
* @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
|
||||
*/
|
||||
async runFlash(isFull,imageData,address,version,checkChip){
|
||||
async runFlash(isFull,imageData,version,checkChip){
|
||||
try {
|
||||
await this.connect();
|
||||
if (checkChip) {
|
||||
await checkChip(this.getChipFamily(),imageData,isFull); //just check
|
||||
}
|
||||
let info= await checkChip(this.getChipId(),imageData,isFull); //just check
|
||||
let fileList = [
|
||||
{ data: imageData, address: address }
|
||||
{ data: imageData, address: info.flashAddress }
|
||||
];
|
||||
let txt = isFull ? "baseImage (all data will be erased)" : "update";
|
||||
if (!confirm(`ready to install ${version}\n${txt}`)) {
|
||||
|
|
Loading…
Reference in New Issue