diff --git a/.github/workflows/PlatformioBuild.yml b/.github/workflows/PlatformioBuild.yml
index 35c9c305..8f3ac4b0 100644
--- a/.github/workflows/PlatformioBuild.yml
+++ b/.github/workflows/PlatformioBuild.yml
@@ -105,4 +105,3 @@ jobs:
# install local version of the library
pio pkg install -e test --no-save --library file://$(realpath ../../../)
pio run -e test
-
diff --git a/README.md b/README.md
index 85a01237..7da59b2c 100644
--- a/README.md
+++ b/README.md
@@ -72,11 +72,12 @@ All those are available in the [Arduino Library Manager](https://www.arduinolibr
-**2) Download the [SD-Content :floppy_disk:](https://github.com/tobozo/M5Stack-SD-Updater/releases/download/v0.4.1/SD-Apps-Folder.zip) folder from the release page and unzip it into the root of the SD Card.** Then put the SD Card into the M5Stack. This zip file comes preloaded with [precompiled apps](https://github.com/tobozo/M5Stack-SD-Updater/tree/master/examples/M5Stack-SD-Menu/SD-Apps) and the relative meta information for the menu.
+**outdated binaries**
+~~**2) Download the [SD-Content :floppy_disk:](https://github.com/tobozo/M5Stack-SD-Updater/releases/download/v0.4.1/SD-Apps-Folder.zip) folder from the release page and unzip it into the root of the SD Card.** Then put the SD Card into the M5Stack. This zip file comes preloaded with [precompiled apps](https://github.com/tobozo/M5Stack-SD-Updater/tree/master/examples/M5Stack-SD-Menu/SD-Apps) and the relative meta information for the menu.~~
-**3) Compile and flash the `M5Stack-SD-Menu.ino` example.**
+**2) Compile and flash the `M5Stack-SD-Menu.ino` example.**
This sketch is the **menu** app. It shoul reside in the root directory of a micro SD card for persistence and also executed once.
Once flashed it will **copy itself** on OTA2 partition and on the SDCard, then rolled back and executed from the OTA2 partition.
@@ -86,7 +87,7 @@ Thanks to @Lovyan03 this self-propagation logic is very convenient: by residing
-**4) Make application sketches compatible with the SD-Updater Menu .**
+**3) Make application sketches compatible with the SD-Updater Menu .**
The snippet of code in the `M5Stack-SDLoader-Snippet.ino` sketch can be used as a model to make any ESP32 sketch compatible with the SD-Updater menu.
diff --git a/examples/M5Stack-FW-Menu/src/main.cpp b/examples/M5Stack-FW-Menu/src/main.cpp
index ca15882e..036df4d2 100644
--- a/examples/M5Stack-FW-Menu/src/main.cpp
+++ b/examples/M5Stack-FW-Menu/src/main.cpp
@@ -401,7 +401,8 @@ void menuItemLoadFW()
{
auto ota_num = slotPicker("Run Flash App", false); // load apps
if( ota_num > 0 ) {
- SDUpdater::_message("Booting partition");
+ String msg = "Booting partition " + String(ota_num);
+ SDUpdater::_message(msg);
if( !Flash::bootPartition( ota_num ) ) {
SDUpdater::_error("Partition unbootable :(");
}
@@ -468,10 +469,10 @@ void menuItemPartitionsInfo()
M5.Lcd.printf("Slot: %d (%s)\n", nvs_part->ota_num, AppName.c_str());
M5.Lcd.printf("Type: 0x%02x\n", part->type);
M5.Lcd.printf("SType: 0x%02x\n", part->subtype);
- M5.Lcd.printf("Addr: 0x%06x\n", part->address);
- M5.Lcd.printf("Size: %d\n", part->size);
+ M5.Lcd.printf("Addr: 0x%06lx\n", part->address);
+ M5.Lcd.printf("Size: %lu\n", part->size);
M5.Lcd.printf("Used: %s\n", meta.image_len>0 ? String(meta.image_len).c_str() : "n/a");
- M5.Lcd.printf("Desc: %s\n", nvs_part->desc[0]!=0?nvs_part->desc:"none");
+ //M5.Lcd.printf("Desc: %s\n", nvs_part->desc[0]!=0?nvs_part->desc:"none");
M5.Lcd.clearClipRect();
@@ -724,7 +725,7 @@ void printFlashPartition( Flash::Partition_t* sdu_partition )
}
}
- Serial.printf("%-8s 0x%02x 0x%02x 0x%06x %8d %8s %8s %8s\n",
+ Serial.printf("%-8s 0x%02x 0x%02x 0x%06lx %8lu %8s %8s %8s\n",
String( part.label ).c_str(),
part.type,
part.subtype,
@@ -746,6 +747,7 @@ void lsFlashPartitions()
}
}
+#include "base64.h"
void lsNVSpartitions()
{
@@ -758,6 +760,36 @@ void lsNVSpartitions()
Serial.printf("[%d] %s slot\n", nvs_part->ota_num, i==0?"Reserved":"Available" );
}
}
+ Serial.println("\nPartitions as CSV:");
+
+
+ size_t blob_size = (sizeof(NVS::PartitionDesc_t)*NVS::Partitions.size());
+ NVS::blob_partition_t *bPart = new NVS::blob_partition_t(blob_size);
+
+ if( !bPart->blob) {
+ log_e("Can't allocate %d bytes for blob", blob_size );
+ return;
+ }
+ size_t idx = 0;
+ for( int i=0; iblob[idx], part, sizeof(NVS::PartitionDesc_t) );
+ }
+
+
+ // https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/storage/nvs_partition_gen.html#csv-file-format
+ String b64 = base64::encode( (const uint8_t*)bPart->blob, blob_size );
+ Serial.printf("Sizeof PartitionDesc_t: %d bytes\n", sizeof(NVS::PartitionDesc_t) );
+ Serial.printf("Sizeof NVS blob: %d bytes\n", blob_size );
+ Serial.printf("Sizeof Base64: %d bytes\n", b64.length() );
+ Serial.println();
+ Serial.println("key,type,encoding,value");// <-- column header
+ Serial.printf("%s,namespace,,\n", NVS::PARTITION_NS ); // <-- First entry should be of type "namespace"
+ Serial.printf("%s,data,base64,%s\n", NVS::PARTITION_KEY, b64.c_str() );
+ Serial.println();
+ // key1,data,u8,1
+ // key2,file,string,/path/to/file
}
@@ -775,6 +807,7 @@ bool checkFactoryStickyPartition()
return false;
}
+ SDUpdater::_message("Checking factory...");
// will compare running partition with factory, and update if necessary
if( SDUpdater::saveSketchToFactory() ) {
// sketch was just saved to factory partition, mark it as bootable and restart
@@ -782,7 +815,7 @@ bool checkFactoryStickyPartition()
log_e("Switching to factory app failed :-(");
return false;
}
-
+ SDUpdater::_message("Checking partitions...");
if( !NVS::getPartitions() ) {
log_w("Partitions not found on NVS, creating"); // first visit!
PartitionManager::createPartitions();
@@ -812,7 +845,9 @@ bool checkOTAStickyPartition()
const esp_partition_t* last_partition = esp_ota_get_next_update_partition(NULL);
- if( !last_partition ) return false;
+ if( !last_partition ) {
+ return false;
+ }
const esp_partition_t* next_partition = Flash::getNextAvailPartition( last_partition->type, last_partition->subtype );
@@ -830,15 +865,12 @@ bool checkOTAStickyPartition()
}
return check_for_migration;
-
}
-
-
void setup()
{
using namespace AppTheme;
@@ -860,7 +892,7 @@ void setup()
SDU_UI::resetScroll();
- SDUpdater::_message("Booting factory...");
+ //SDUpdater::_message("Booting factory...");
if( ! checkFactoryStickyPartition() ) {
// print partitions for debug
@@ -883,12 +915,6 @@ void setup()
void loop()
{
- auto ota_num = slotPicker("Run Application", false); // load apps
- if( ota_num > 0 ) {
- SDUpdater::_message("Booting partition");
- if( !Flash::bootPartition( ota_num ) ) {
- SDUpdater::_error("Partition unbootable :(");
- }
- }
+ menuItemLoadFW();
launcherPicker();
}
diff --git a/src/M5StackUpdater.hpp b/src/M5StackUpdater.hpp
index 0136bc5c..db163ed4 100644
--- a/src/M5StackUpdater.hpp
+++ b/src/M5StackUpdater.hpp
@@ -96,7 +96,7 @@
#define resetReason (int)rtc_get_reset_reason(0)
// use `#define SDU_NO_PRAGMAS` to disable duplicate pragma messages
-#if !defined SDU_NO_PRAGMAS
+#if !defined SDU_NO_PRAGMAS && CORE_DEBUG_LEVEL>=ARDUHAL_LOG_LEVEL_ERROR
#define SDU_STRINGIFY(a) #a
#define SDU_PRAGMA_MESSAGE(msg) \
_Pragma( SDU_STRINGIFY( message msg ) )
diff --git a/src/PartitionManager/NVS/NVSUtils.cpp b/src/PartitionManager/NVS/NVSUtils.cpp
index 82862c7f..a19ade97 100644
--- a/src/PartitionManager/NVS/NVSUtils.cpp
+++ b/src/PartitionManager/NVS/NVSUtils.cpp
@@ -81,13 +81,15 @@ namespace SDUpdaterNS
}
+
+
bool getPartitions()
{
if( Partitions.size()>0 )
Partitions.clear();
size_t blob_size;
- char* out = nullptr;
bool ret = false;
+ blob_partition_t *bPart = nullptr;
auto err = nvs_open(PARTITION_NS, NVS_READONLY, &handle);
if( err != ESP_OK ) {
log_i("NVS Namespace not created yet");
@@ -100,22 +102,23 @@ namespace SDUpdaterNS
goto _nvs_close;
}
- out = (char*)calloc(blob_size+1, sizeof(char));
- if (!out ) {
- log_e("Could not alloc %d bytes", blob_size+1 );
+ bPart = new blob_partition_t( blob_size );
+ if (!bPart->blob ) {
+ log_e("Could not alloc %d bytes", blob_size );
goto _nvs_close;
}
- err = nvs_get_blob(handle, PARTITION_KEY, out, &blob_size);
+
+ err = nvs_get_blob(handle, PARTITION_KEY, bPart->blob, &blob_size);
if( err != ESP_OK ) {
log_e("Could not read blob");
goto _nvs_close;
}
- ret = parsePartitions( out, blob_size-1 );
- free( out );
+ ret = parsePartitions( bPart->blob, blob_size );
_nvs_close:
nvs_close( handle );
+ if( bPart!=nullptr ) delete bPart;
return ret;
}
@@ -145,9 +148,10 @@ namespace SDUpdaterNS
bool ret = true;
if( Partitions.size() > 0 ) {
log_d("Saving partitions");
- size_t blob_size = (sizeof(PartitionDesc_t)*Partitions.size()) + 1;
- char* blob = (char*)calloc(blob_size, sizeof(char));
- if( !blob) {
+ size_t blob_size = (sizeof(PartitionDesc_t)*Partitions.size());
+ blob_partition_t *bPart = new blob_partition_t(blob_size);
+
+ if( !bPart->blob) {
log_e("Can't allocate %d bytes for blob", blob_size );
return false;
}
@@ -155,7 +159,7 @@ namespace SDUpdaterNS
for( int i=0; iblob[idx], part, sizeof(PartitionDesc_t) );
}
auto err = nvs_open(PARTITION_NS, NVS_READWRITE, &handle);
@@ -164,7 +168,7 @@ namespace SDUpdaterNS
return false;
}
- err = nvs_set_blob(handle, PARTITION_KEY, blob, blob_size);
+ err = nvs_set_blob(handle, PARTITION_KEY, bPart->blob, blob_size);
if( err != ESP_OK ) {
log_e("Failed to save blob");
ret = false;
@@ -174,7 +178,7 @@ namespace SDUpdaterNS
}
nvs_close( handle );
- free( blob );
+ delete bPart;
}
return ret;
}
diff --git a/src/PartitionManager/NVS/NVSUtils.hpp b/src/PartitionManager/NVS/NVSUtils.hpp
index a670b1f7..4d495dba 100644
--- a/src/PartitionManager/NVS/NVSUtils.hpp
+++ b/src/PartitionManager/NVS/NVSUtils.hpp
@@ -38,7 +38,28 @@ namespace SDUpdaterNS
size_t bin_size{0}; // firmware size
uint8_t digest[32]{0}; // firmware digest
char name[40]{0}; // firmware name
- char desc[40]{0}; // firmware desc
+ //char desc[40]{0}; // firmware desc
+ };
+
+ struct blob_partition_t
+ {
+ char* blob{nullptr};
+ bool needs_free{false};
+ blob_partition_t() : blob(nullptr), needs_free(false) { }
+ blob_partition_t( size_t blob_size ) : blob(nullptr), needs_free(false)
+ {
+ this->blob = (char*)calloc(blob_size+1, sizeof(char));
+ if (!this->blob ) {
+ log_e("Could not alloc %d bytes", blob_size );
+ } else {
+ needs_free = true;
+ }
+ }
+ ~blob_partition_t()
+ {
+ if( needs_free )
+ free(this->blob);
+ }
};
extern nvs_handle_t handle;
diff --git a/src/PartitionManager/PartitionManager.cpp b/src/PartitionManager/PartitionManager.cpp
index f4efda7f..916e75b5 100644
--- a/src/PartitionManager/PartitionManager.cpp
+++ b/src/PartitionManager/PartitionManager.cpp
@@ -25,11 +25,12 @@ namespace SDUpdaterNS
if( Flash::metadataHasDigest( meta ) ) {
nvs_part.bin_size = meta->image_len;
memcpy( nvs_part.digest, meta->image_digest, 32 );
- log_d("Added flash digest to NVS::Partitions[]: %s", digests.toString( nvs_part.digest ) );
+ log_d("Added flash digest to NVS::Partitions[%d]: %s", NVS::Partitions.size(), digests.toString( nvs_part.digest ) );
}
NVS::Partitions.push_back( nvs_part );
}
NVS::savePartitions();
+ //debugPartitions();
log_i("Partition scheme has %d app slot(s)", NVS::Partitions.size() );
}
@@ -62,6 +63,7 @@ namespace SDUpdaterNS
if( needs_saving ) {
NVS::savePartitions();
+ //debugPartitions();
}
}
@@ -84,6 +86,7 @@ namespace SDUpdaterNS
nvs_part->bin_size = 0;
memset( nvs_part->digest, 0, 32 );
if( NVS::savePartitions() ) {
+ //debugPartitions();
// TODO: implement partitions reload instead of restart
ESP.restart();
}
@@ -123,7 +126,8 @@ namespace SDUpdaterNS
log_e("WARN: partition has no sha");
//return false;
}
- return NVS::savePartitions();
+ ret = NVS::savePartitions();
+ //debugPartitions();
}
return ret;
}
@@ -203,21 +207,83 @@ namespace SDUpdaterNS
}
+ // void debugPartitions()
+ // {
+ // log_d("OTA, size, digest, name, desc");
+ // Flash::digest_t digests;
+ // for( int i=0;ipart;
+ // auto meta = sdu_partition->meta;
+ //
+ // String AppName = "n/a";
+ //
+ // if( Flash::partitionIsApp( &part ) ) {
+ // if( Flash::partitionIsFactory( &part ) ) {
+ // AppName = "Factory";
+ // } else {
+ // AppName = "OTA" + String( part.subtype - ESP_PARTITION_SUBTYPE_APP_OTA_MIN );
+ // }
+ // }
+ //
+ // log_d("%-8s 0x%02x 0x%02x 0x%06x %8d %8s %8s %8s",
+ // String( part.label ).c_str(),
+ // part.type,
+ // part.subtype,
+ // part.address,
+ // part.size,
+ // meta.image_len>0 ? String(meta.image_len).c_str() : "n/a",
+ // AppName.c_str(),
+ // Flash::partitionIsApp(&part)&&Flash::metadataHasDigest(&meta) ? digests.toString(meta.image_digest) : "n/a"
+ // );
+ // }
+ // }
+
+
bool erase( uint8_t ota_num )
{
NVS::PartitionDesc_t* nvs_part = NVS::findPartition(ota_num);
- if( !nvs_part ) return false;
+ if( !nvs_part ) {
+ log_e("Cannot erase partition, NVS::findPartition(%d) found nothing", ota_num);
+ return false;
+ }
auto flash_part = Flash::getPartition( ota_num );
- if( !flash_part ) return false;
+ if( !flash_part ) {
+ log_e("Cannot erase partition, Flash::getPartition(%d) found nothing", ota_num);
+ return false;
+ }
if( Flash::erase(ota_num) ) {
+
nvs_part->bin_size = 0;
nvs_part->name[0] = 0;
- nvs_part->desc[0] = 0;
+ //nvs_part->desc[0] = 0;
for( int i=0;i<32;i++ ) nvs_part->digest[i] = 0;
+
+ Flash::scan();
+ //debugPartitions();
+
if( NVS::savePartitions() ) {
log_d("TODO: implement partitions reload instead of restart");
+ //debugPartitions();
ESP.restart(); // force partition reload
}
+ } else {
+ log_e("Could erase partition, Flash::erase(%d) failed", ota_num);
}
return false;
}
@@ -246,12 +312,17 @@ namespace SDUpdaterNS
bool migrateSketch( const char* binFileName )
{
assert(binFileName);
+ log_v("Checking %s for migration", binFileName);
Flash::digest_t digests = Flash::digest_t();
if( !canMigrateToFactory() ) {
return false; // need a factory partition scheme
}
+ if( !NVS::getPartitions() ) {
+ return false; // need a NVS partition management already set
+ }
+
esp_image_metadata_t running_meta;
esp_image_metadata_t dst_meta;
@@ -262,35 +333,44 @@ namespace SDUpdaterNS
size_t sksize = 0;
String error = "";
+ String msg = "";
Flash::running_partition = esp_ota_get_running_partition();
if( !Flash::running_partition ) {
log_e("Flash inconsistency: running partition not found" );
return false; // uh-oh
}
+
+ if( Flash::running_partition->subtype != ESP_PARTITION_SUBTYPE_APP_OTA_MIN ) {
+
+ }
+
+
running_meta = Flash::getSketchMeta( Flash::running_partition );
NVSPart = NVS::findPartition( binFileName );
- if( !NVSPart ) {
+ if( !NVSPart /*|| (NVSPart && digests.isEmpty( NVSPart->digest))*/ ) {
// No NVS partition found named [binFilename], but NVS may be wrong so try to also find by digest
FlashPart = Flash::findDupePartition( &running_meta, Flash::running_partition->type, Flash::running_partition->subtype );
if( FlashPart ) {
//log_d("Duplicate partition found: NVS has no entry named %s but partition meta %d exists", binFileName, FlashPart->part.subtype - ESP_PARTITION_SUBTYPE_APP_OTA_MIN );
- error = "Error: NVS dupe found";
+ error = "Error: NVS dupe found, please erase NVS";
goto _error_nvs;
}
+ log_d("NVS Partition named %s not found", binFileName );
// new slot, get next flashable partition
Flash::nextupd_partition = Flash::getNextAvailPartition( Flash::running_partition->type, Flash::running_partition->subtype );
if( !Flash::nextupd_partition ) {
- error = "Partitions full";//migration to new slot is not possible
+ error = "Migration canceled: partitions full";//migration to new slot is not possible
goto _error_nvs;
}
// store NVS app number
ota_num = Flash::nextupd_partition->subtype - ESP_PARTITION_SUBTYPE_APP_OTA_MIN;
sksize = ESP.getSketchSize();
- SDUpdater::_message( String("Migrating to new slot") );
+ msg = String("Migrating to new slot #") + String(ota_num);
+ SDUpdater::_message( msg );
// copy to next partition
if( !Flash::copyPartition( Flash::nextupd_partition, Flash::running_partition, sksize) ) {
@@ -337,20 +417,27 @@ namespace SDUpdaterNS
FlashPart = Flash::findDupePartition( &running_meta, Flash::running_partition->type, Flash::running_partition->subtype );
if( FlashPart ) {
// erase duplicate (will trigger a restart on success)
- SDUpdater::_message( String("Erasing old partition") );
- if( !PartitionManager::erase( FlashPart->part.subtype -ESP_PARTITION_SUBTYPE_APP_OTA_MIN ) ) {
+ msg = String("Erasing old partition");
+ SDUpdater::_message( msg );
+ if( !PartitionManager::erase( FlashPart->part.subtype - ESP_PARTITION_SUBTYPE_APP_OTA_MIN ) ) {
error = "Erasing failed!";
goto _error_nvs;
}
+
}
- log_d("this sketch is already running from the right partition according to NVS");
+ log_i("this sketch is already running from the right partition (%d) according to NVS", ota_num);
return false;
}
- // log_d("Current sketch is not running from its assigned partition (NVS want=%d, has=%d)", ota_num, Flash::running_partition->subtype - ESP_PARTITION_SUBTYPE_APP_OTA_MIN );
+ log_w("Current sketch is not running from its assigned partition (NVS want=%d, has=%d)", ota_num, Flash::running_partition->subtype - ESP_PARTITION_SUBTYPE_APP_OTA_MIN );
// overwrite if digests differ
if( ! digests.match( NVSPart->digest, running_meta.image_digest ) ) {
+ msg = "Overwriting slot (in=";
+ msg += digests.toString( NVSPart->digest );
+ msg += ", out=";
+ msg += digests.toString( running_meta.image_digest );
+ msg += ")";
SDUpdater::_message( String("Overwriting slot") );
sksize = ESP.getSketchSize();
if( !Flash::copyPartition( Flash::nextupd_partition, Flash::running_partition, sksize) ) {
@@ -359,7 +446,7 @@ namespace SDUpdaterNS
}
goto _update_nvs;
} else {
- // log_d("names and digests match, no overwrite, just switch");
+ log_d("names and digests match, no overwrite, just switch");
goto _boot_partition;
}
@@ -372,7 +459,9 @@ namespace SDUpdaterNS
NVSPart->bin_size = running_meta.image_len;
memcpy( NVSPart->digest, running_meta.image_digest, 32 );
snprintf( NVSPart->name, 39, "%s", binFileName );
+ log_d("Updated NVSPart->name %s=%s", NVSPart->name, binFileName);
NVS::savePartitions();
+ //debugPartitions();
_boot_partition:
diff --git a/src/PartitionManager/PartitionManager.hpp b/src/PartitionManager/PartitionManager.hpp
index 2ee7ad04..0e107a66 100644
--- a/src/PartitionManager/PartitionManager.hpp
+++ b/src/PartitionManager/PartitionManager.hpp
@@ -18,6 +18,7 @@ namespace SDUpdaterNS
void createPartitions();
void updatePartitions();
void processPartitions();
+ void debugPartitions();
bool flashFactory();
bool migrateSketch( const char* binFileName );
diff --git a/src/PartitionManager/Partitions/PartitionUtils.cpp b/src/PartitionManager/Partitions/PartitionUtils.cpp
index 174f1dcb..dbcdad1e 100644
--- a/src/PartitionManager/Partitions/PartitionUtils.cpp
+++ b/src/PartitionManager/Partitions/PartitionUtils.cpp
@@ -3,6 +3,10 @@
#include "../../ConfigManager/ConfigManager.hpp"
+#if !defined SPI_FLASH_SEC_SIZE
+ #define SPI_FLASH_SEC_SIZE 4096
+#endif
+
namespace SDUpdaterNS
{
@@ -601,17 +605,23 @@ namespace SDUpdaterNS
}
-
- bool erase( uint8_t ota_num )
+ bool erase( const esp_partition_t *part )
{
- auto part = getPartition( ota_num );
- log_d("Erasing ota partition %d (%#x)", ota_num, part->subtype );
+ assert(part);
+ log_d("Erasing ota partition %#x", part->subtype );
if( part && ESP.partitionEraseRange(part, 0, part->size ) ) {
return true;
}
- log_e("FATAL: can't erase running partition");
+ log_e("FATAL: can't erase partition");
return false;
}
+
+ bool erase( uint8_t ota_num )
+ {
+ auto part = getPartition( ota_num );
+ return erase( part );
+ }
+
};
};
diff --git a/src/PartitionManager/Partitions/PartitionUtils.hpp b/src/PartitionManager/Partitions/PartitionUtils.hpp
index 5af7ea27..b636b9ab 100644
--- a/src/PartitionManager/Partitions/PartitionUtils.hpp
+++ b/src/PartitionManager/Partitions/PartitionUtils.hpp
@@ -3,6 +3,7 @@
#include
#include
#include
+#include
extern "C" {
#include "esp_ota_ops.h"
#include "esp_image_format.h"
@@ -45,6 +46,7 @@ namespace SDUpdaterNS
bool bootPartition( uint8_t ota_num );
bool erase( uint8_t ota_num );
+ bool erase( const esp_partition_t *part );
bool copyPartition(fs::FS *fs, const char* binfilename); // copy from OTA0 to OTA1 and filesystem
bool copyPartition(fs::File* dstFile, const esp_partition_t* src, size_t length); // copy from given partition to filesystem
diff --git a/src/SDUpdater/SDUpdater_Class.cpp b/src/SDUpdater/SDUpdater_Class.cpp
index f4af8cab..1f16e74f 100644
--- a/src/SDUpdater/SDUpdater_Class.cpp
+++ b/src/SDUpdater/SDUpdater_Class.cpp
@@ -312,6 +312,12 @@ namespace SDUpdaterNS
{
bool hasFileName = (fileName!="");
+ // if using factory: disable "Save FW" action button when running partition isn't the first partition
+ SDUCfg.Buttons[2].enabled = cfg->rollBackToFactory
+ ? esp_ota_get_running_partition()->subtype==ESP_PARTITION_SUBTYPE_APP_OTA_MIN
+ : SDUCfg.Buttons[2].enabled
+ ;
+
if( cfg->onWaitForAction ) {
int action = cfg->onWaitForAction( !hasFileName ? (char*)cfg->labelRollback : (char*)cfg->labelMenu, (char*)cfg->labelSkip, (char*)cfg->labelSave, SDUCfg.waitdelay );
@@ -335,7 +341,7 @@ namespace SDUpdaterNS
log_v("Checking if %s needs saving", cfg->binFileName );
saveSketchToFS( *cfg->fs, cfg->binFileName, action != ConfigManager::SDU_BTNC_SAVE );
} else if( cfg->rollBackToFactory ) {
- return PartitionManager::migrateSketch( fileName.c_str() );
+ return PartitionManager::migrateSketch( cfg->binFileName );
} else if( action == ConfigManager::SDU_BTNC_SAVE ) {
const char* msg[] = {"No valid filesystem", "selected!", "Cannot save", fileName.c_str()};
_error( msg, 4 );