diff --git a/extra_script.py b/extra_script.py
index 8a50062..a91c147 100644
--- a/extra_script.py
+++ b/extra_script.py
@@ -268,7 +268,10 @@ 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)])
+ env.Append(CPPDEFINES=[
+ ('GWDEVVERSION',version),
+ ('PIO_ENV_BOARD',env.get('BOARD_MCU'))
+ ])
def cleangenerated(source, target, env):
od=outPath()
@@ -290,3 +293,4 @@ env.Append(
)
#script does not run on clean yet - maybe in the future
env.AddPostAction("clean",cleangenerated)
+#print(env.Dump())
diff --git a/lib/appinfo/GwAppInfo.h b/lib/appinfo/GwAppInfo.h
index 12ff16d..79e4622 100644
--- a/lib/appinfo/GwAppInfo.h
+++ b/lib/appinfo/GwAppInfo.h
@@ -15,4 +15,9 @@
#endif
#endif
-#define FIRMWARE_TYPE GWSTRINGIFY(PIO_ENV_BUILD)
\ No newline at end of file
+#define FIRMWARE_TYPE GWSTRINGIFY(PIO_ENV_BUILD)
+#ifdef PIO_ENV_BOARD
+#define BOARD_INFO "@@" GWSTRINGIFY(PIO_ENV_BOARD)
+#else
+#define BOARD_INFO ""
+#endif
\ No newline at end of file
diff --git a/src/main.cpp b/src/main.cpp
index b3b29b7..f42a363 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -76,6 +76,7 @@ const unsigned long HEAP_REPORT_TIME=2000; //set to 0 to disable heap reporting
//assert length of firmware name and version
CASSERT(strlen(FIRMWARE_TYPE) <= 32, "environment name (FIRMWARE_TYPE) must not exceed 32 chars");
CASSERT(strlen(VERSION) <= 32, "VERSION must not exceed 32 chars");
+CASSERT(strlen(BOARD_INFO) <= 32,"BOARD_INFO must not exceed 32 chars");
//https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/system/app_image_format.html
//and removed the bugs in the doc...
__attribute__((section(".rodata_custom_desc"))) esp_app_desc_t custom_app_desc = {
@@ -86,7 +87,7 @@ __attribute__((section(".rodata_custom_desc"))) esp_app_desc_t custom_app_desc =
FIRMWARE_TYPE,
"00:00:00",
"2021/12/13",
- "0000",
+ BOARD_INFO,
{},
{}
};
diff --git a/webinstall/install.css b/webinstall/install.css
index 26a1a45..6731764 100644
--- a/webinstall/install.css
+++ b/webinstall/install.css
@@ -35,4 +35,11 @@ body {
}
.hidden{
display: none !important;
+}
+.uploadFile{
+ width: 0;
+ height: 0;
+}
+.uploadButton{
+ margin-left: 0.5em;
}
\ No newline at end of file
diff --git a/webinstall/install.html b/webinstall/install.html
index da4d0bd..be9dc94 100644
--- a/webinstall/install.html
+++ b/webinstall/install.html
@@ -11,11 +11,12 @@
+
+
+
loading data
+

+
-
-
-

-
diff --git a/webinstall/install.js b/webinstall/install.js
index 95929df..059e431 100644
--- a/webinstall/install.js
+++ b/webinstall/install.js
@@ -11,7 +11,8 @@ 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 MINSIZE = HDROFFSET + NAMEOFFSET + 32;
+ const CHIPOFFSET=NAMEOFFSET+64;
+ const MINSIZE = HDROFFSET + CHIPOFFSET + 32;
const imageCheckBytes = {
0: 0xe9, //image magic
288: 0x32, //app header magic
@@ -46,12 +47,24 @@ 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
};
return rt;
}
+ const readFile=(file)=>{
+ return new Promise((resolve,reject)=>{
+ let reader = new FileReader();
+ reader.addEventListener('load', function (e) {
+ resolve(e.target.result);
+
+ });
+ reader.readAsBinaryString(file);
+ });
+ }
const checkImageFile=(file,isFull)=>{
let minSize=MINSIZE+(isFull?(UPDATE_START-FULL_START):0);
return new Promise(function (resolve, reject) {
@@ -97,12 +110,22 @@ 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=(chipFamily,assetName)=>{
- //for now only ESP32
- if (chipFamily != "ESP32"){
- throw new Error(`unexpected chip family ${chipFamily}, expected ESP32`);
+ const checkChip= async (chipFamily,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;
}
- return assetName;
+ //for now only ESP32/ESP32-S3
+ if (chipFamily != "ESP32" && chipFamily != "ESP32-S3"){
+ throw new Error(`unexpected chip family ${chipFamily}, expected ESP32/ESP32-S3`);
+ }
+ return;
}
const baudRates=[1200,
2400,
@@ -138,6 +161,63 @@ import * as zip from "https://cdn.jsdelivr.net/npm/@zip.js/zip.js@2.7.29/+esm";
enableConsole(true);
})
}
+ const handleLocalFile= async (file)=>{
+ setValue('content','');
+ showLoading("loading "+file.name);
+ try {
+ if (file.name.match(/.zip$/)) {
+ //zip
+ await handleZip(file);
+ }
+ else {
+ if (! file.name.match(/\.bin$/)){
+ throw new Error("only .zip or .bin");
+ }
+ let data=await readFile(file);
+ let isFull=false;
+ let info;
+ try{
+ info=checkImage(data,true);
+ isFull=true;
+ }catch (e){
+ try{
+ info=checkImage(data);
+ }
+ catch(x){
+ throw new Error(file.name+" is no image: "+x);
+ }
+ }
+ if (isFull){
+ buildCustomButtons("dummy",undefined,data,file.name,"Local");
+ }
+ else{
+ buildCustomButtons("dummy",data,undefined,file.name,"Local");
+ }
+ }
+ } catch (e) {
+ alert(e);
+ }
+ showLoading();
+ }
+ const buildUploadButtons= (element)=>{
+ let bFrame=document.querySelector(element||'.upload');
+ if (! bFrame) return;
+ bFrame.textContent='';
+ let it=addEl('div','item',bFrame);
+ addEl('div','version',it,`Local File`);
+ let cLine=addEl('div','buttons',it);
+ let fi=addEl('input','uploadFile',cLine);
+ fi.setAttribute('type','file');
+ fi.addEventListener('change',async (ev)=>{
+ let files=ev.target.files;
+ if (files.length < 1) return;
+ await handleLocalFile(files[0]);
+ });
+ let bt=addEl('button','uploadButton',cLine,'upload');
+ bt.addEventListener('click',()=>{
+ fi.click();
+ });
+ }
const buildButtons=(user,repo,element)=>{
let bFrame=document.querySelector(element||'.content');
if (! bFrame) return;
@@ -148,7 +228,7 @@ import * as zip from "https://cdn.jsdelivr.net/npm/@zip.js/zip.js@2.7.29/+esm";
alert("no version found in release data");
return;
}
- addEl('div','version',bFrame,`Version: ${version}`);
+ addEl('div','version',bFrame,`Prebuild: ${version}`);
let items={};
releaseData.assets.forEach((asset)=>{
let name=asset.name;
@@ -179,7 +259,7 @@ import * as zip from "https://cdn.jsdelivr.net/npm/@zip.js/zip.js@2.7.29/+esm";
repo,
version,
4096,
- (chip)=>checkChip(chip,item.basic)
+ checkChip
)
enableConsole(true);
});
@@ -192,56 +272,75 @@ import * as zip from "https://cdn.jsdelivr.net/npm/@zip.js/zip.js@2.7.29/+esm";
repo,
version,
65536,
- (chip)=>checkChip(chip,item.update)
+ checkChip
)
enableConsole(true);
});
}
}
- const buildCustomButtons = (name, updateData, fullData,info,element) => {
+ const buildCustomButtons = (name, updateData, fullData,info,title,element) => {
let bFrame = document.querySelector(element || '.content');
if (!bFrame) return;
- let vinfo=checkImage(fullData,true);
- let version=vinfo.version;
- let uinfo=checkImage(updateData);
- if (uinfo.version != version){
- throw new Error("different versions in full("+version+") and update("+uinfo.version+") image");
+ if (fullData === undefined && updateData === undefined) return;
+ let version;
+ if (fullData !== undefined){
+ let vinfo=checkImage(fullData,true);
+ version=vinfo.version;
+ }
+ if (updateData !== undefined){
+ let uinfo=checkImage(updateData);
+ if (version !== undefined){
+ if (uinfo.version != version){
+ throw new Error("different versions in full("+version+") and update("+uinfo.version+") image");
+ }
+ }
+ else{
+ version=uinfo.version;
+ }
}
bFrame.textContent = '';
let item=addEl('div','item',bFrame);
- addEl('div', 'version', item, "Custom "+version);
+ addEl('div', 'version', item, title+" "+version);
if (info){
addEl('div','version',item,info);
}
let btLine = addEl('div', 'buttons', item);
- let tb = addEl('button', 'installButton', btLine, 'Initial');
- tb.addEventListener('click', async () => {
- enableConsole(false, true);
- await espInstaller.runFlash(
- true,
- fullData,
- FULL_START,
- version,
- (ch) => checkChip(ch, name)
- )
- enableConsole(true);
- });
- tb = addEl('button', 'installButton', btLine, 'Update');
- tb.addEventListener('click', async () => {
- enableConsole(false, true);
- await espInstaller.runFlash(
- false,
- updateData,
- UPDATE_START,
- version,
- (ch) => checkChip(ch, name)
- )
- enableConsole(true);
- });
+ let tb;
+ if (fullData !== undefined) {
+ tb = addEl('button', 'installButton', btLine, 'Initial');
+ tb.addEventListener('click', async () => {
+ enableConsole(false, true);
+ await espInstaller.runFlash(
+ true,
+ fullData,
+ FULL_START,
+ version,
+ checkChip
+ )
+ enableConsole(true);
+ });
+ }
+ if (updateData !== undefined) {
+ tb = addEl('button', 'installButton', btLine, 'Update');
+ tb.addEventListener('click', async () => {
+ enableConsole(false, true);
+ await espInstaller.runFlash(
+ false,
+ updateData,
+ UPDATE_START,
+ version,
+ checkChip
+ )
+ enableConsole(true);
+ });
+ }
}
- const showLoading=(on)=>{
- setVisible('loadingFrame',on);
+ const showLoading=(title)=>{
+ setVisible('loadingFrame',title !== undefined);
+ if (title){
+ setValue('loadingText',title);
+ }
};
class BinaryStringWriter extends zip.Writer {
@@ -260,6 +359,51 @@ import * as zip from "https://cdn.jsdelivr.net/npm/@zip.js/zip.js@2.7.29/+esm";
return this.binaryString;
}
}
+ const handleZip = async (zipFile) => {
+ showLoading("loading zip");
+ let reader;
+ let title="Custom";
+ if (typeof(zipFile) === 'string'){
+ setValue('loadingText', 'downloading custom build')
+ reader= new zip.HttpReader(zipFile);
+ }
+ else{
+ setValue('loadingText', 'loading zip file');
+ reader = new zip.BlobReader(zipFile);
+ title="Local";
+ }
+ let zipReader = new zip.ZipReader(reader);
+ const entries = (await zipReader.getEntries());
+ let fullData;
+ let updateData;
+ let base = "";
+ let environment;
+ let buildflags;
+ for (let i = 0; i < entries.length; i++) {
+ if (entries[i].filename.match(/-all.bin$/)) {
+ fullData = await (entries[i].getData(new BinaryStringWriter()));
+ base = entries[i].filename.replace("-all.bin", "");
+ }
+ if (entries[i].filename.match(/-update.bin$/)) {
+ updateData = await (entries[i].getData(new BinaryStringWriter()));
+ base = entries[i].filename.replace("-update.bin", "");
+ }
+ if (entries[i].filename === 'buildconfig.txt') {
+ let txt = await (entries[i].getData(new zip.TextWriter()));
+ environment = txt.replace(/.*pio run *.e */, '').replace(/ .*/, '');
+ buildflags = txt.replace(/.*PLATFORMIO_BUILD_FLAGS="/, '').replace(/".*/, '');
+ }
+ }
+ let info;
+ if (environment !== undefined && buildflags !== undefined) {
+ info = `env=${environment}, flags=${buildflags}`;
+ }
+ if (updateData === undefined && fullData === undefined){
+ throw new Error("no firmware files found in zip");
+ }
+ buildCustomButtons("dummy", updateData, fullData, info,title);
+ showLoading();
+ }
window.onload = async () => {
if (! ESPInstaller.checkAvailable()){
showError("your browser does not support the ESP flashing (no serial)");
@@ -280,47 +424,19 @@ import * as zip from "https://cdn.jsdelivr.net/npm/@zip.js/zip.js@2.7.29/+esm";
espLoaderTerminal = new XtermOutputHandler('terminal');
espInstaller = new ESPInstaller(espLoaderTerminal);
buildConsoleButtons();
+ buildUploadButtons();
if (! custom){
buildHeading(`${user}:${repo}`);
releaseData = await espInstaller.getReleaseInfo(user, repo);
buildButtons(user, repo);
+ showLoading();
}
else{
errorText="unable to download custom build";
- showLoading(true);
- setValue('loadingText','downloading custom build')
- let reader= new zip.HttpReader(custom);
- let zipReader= new zip.ZipReader(reader);
- const entries=(await zipReader.getEntries());
- let fullData;
- let updateData;
- let base="";
- let environment;
- let buildflags;
- for (let i=0;i