add handling for board type to images and webflasher
This commit is contained in:
parent
0d5343ddf4
commit
2b42cc53e7
|
@ -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())
|
||||
|
|
|
@ -16,3 +16,8 @@
|
|||
#endif
|
||||
|
||||
#define FIRMWARE_TYPE GWSTRINGIFY(PIO_ENV_BUILD)
|
||||
#ifdef PIO_ENV_BOARD
|
||||
#define BOARD_INFO "@@" GWSTRINGIFY(PIO_ENV_BOARD)
|
||||
#else
|
||||
#define BOARD_INFO ""
|
||||
#endif
|
|
@ -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,
|
||||
{},
|
||||
{}
|
||||
};
|
||||
|
|
|
@ -36,3 +36,10 @@ body {
|
|||
.hidden{
|
||||
display: none !important;
|
||||
}
|
||||
.uploadFile{
|
||||
width: 0;
|
||||
height: 0;
|
||||
}
|
||||
.uploadButton{
|
||||
margin-left: 0.5em;
|
||||
}
|
|
@ -11,11 +11,12 @@
|
|||
<body>
|
||||
<div class="heading"></div>
|
||||
<div class="console"></div>
|
||||
<div class="upload"></div>
|
||||
<div id="loadingFrame">
|
||||
<div id="loadingText" >loading data</div>
|
||||
<img id="loading" src="spinner.gif"/>
|
||||
</div>
|
||||
<div class="content">
|
||||
<div id="loadingFrame">
|
||||
<div id="loadingText" ></div>
|
||||
<img id="loading" src="spinner.gif"/>
|
||||
</div>
|
||||
</div>
|
||||
<div id="terminal"></div>
|
||||
</body>
|
||||
|
|
|
@ -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<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}`;
|
||||
}
|
||||
buildCustomButtons("dummy",updateData,fullData,info);
|
||||
showLoading(false);
|
||||
await handleZip(custom);
|
||||
}
|
||||
} catch(error){
|
||||
showLoading(false);
|
||||
showLoading();
|
||||
alert(errorText+error)
|
||||
};
|
||||
}
|
||||
|
|
|
@ -236,22 +236,19 @@ class ESPInstaller{
|
|||
* @param {*} repo
|
||||
* @param {*} version
|
||||
* @param {*} address
|
||||
* @param {*} assetName the name of the asset file.
|
||||
* can be a function - will be called with the chip family
|
||||
* and must return the asset file name
|
||||
* @param {*} checkChip will be called with the found chip and the data and the isFull flag
|
||||
* @returns
|
||||
*/
|
||||
async installClicked(isFull, user, repo, version, address, assetName) {
|
||||
try {
|
||||
await this.connect();
|
||||
let assetFileName = assetName;
|
||||
if (typeof (assetName) === 'function') {
|
||||
assetFileName = assetName(this.getChipFamily());
|
||||
}
|
||||
let imageData = await this.getReleaseAsset(user, repo, version, assetFileName);
|
||||
let imageData = await this.getReleaseAsset(user, repo, version, assetName);
|
||||
if (!imageData || imageData.length == 0) {
|
||||
throw new Error(`no image data fetched`);
|
||||
}
|
||||
if (checkChip) {
|
||||
await checkChip(this.getChipFamily(),imageData,isFull);
|
||||
}
|
||||
let fileList = [
|
||||
{ data: imageData, address: address }
|
||||
];
|
||||
|
@ -274,13 +271,14 @@ class ESPInstaller{
|
|||
* @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
|
||||
* @returns
|
||||
*/
|
||||
async runFlash(isFull,imageData,address,version,assetName){
|
||||
async runFlash(isFull,imageData,address,version,checkChip){
|
||||
try {
|
||||
await this.connect();
|
||||
if (typeof (assetName) === 'function') {
|
||||
assetName(this.getChipFamily()); //just check
|
||||
if (checkChip) {
|
||||
await checkChip(this.getChipFamily(),imageData,isFull); //just check
|
||||
}
|
||||
let fileList = [
|
||||
{ data: imageData, address: address }
|
||||
|
|
Loading…
Reference in New Issue