diff --git a/extra_script.py b/extra_script.py index a91c147..8a50062 100644 --- a/extra_script.py +++ b/extra_script.py @@ -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()) diff --git a/tools/flashtool/flashtool.py b/tools/flashtool/flashtool.py index 3a30162..92fef05 100755 --- a/tools/flashtool/flashtool.py +++ b/tools/flashtool/flashtool.py @@ -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) diff --git a/web/index.js b/web/index.js index 699a82e..4c49f9c 100644 --- a/web/index.js +++ b/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"); diff --git a/webinstall/install.js b/webinstall/install.js index 6db2cb1..fb84eeb 100644 --- a/webinstall/install.js +++ b/webinstall/install.js @@ -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 ) diff --git a/webinstall/installUtil.js b/webinstall/installUtil.js index bb0eedd..c46f2af 100644 --- a/webinstall/installUtil.js +++ b/webinstall/installUtil.js @@ -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}`)) {