diff --git a/.github/workflows/ArduinoBuild.yml b/.github/workflows/ArduinoBuild.yml index 860d38c1..9089fbd6 100644 --- a/.github/workflows/ArduinoBuild.yml +++ b/.github/workflows/ArduinoBuild.yml @@ -29,9 +29,10 @@ jobs: #- 2.0.3 #- 2.0.4 #- 2.0.5 - - 2.0.6 + #- 2.0.6 - 2.0.7 - 2.0.8 + - 2.0.9 matrix-context: - M5Core2-test @@ -65,9 +66,10 @@ jobs: #- sdk-version: 2.0.0 #- sdk-version: 2.0.1 #- sdk-version: 2.0.5 - - sdk-version: 2.0.6 + #- sdk-version: 2.0.6 - sdk-version: 2.0.7 - sdk-version: 2.0.8 + - sdk-version: 2.0.9 # library health test sketches - { matrix-context: M5Core2-test, arduino-board: m5stack-core2, sketch-names: M5Core2-SDLoader-Snippet.ino, required-libraries: "M5Core2", ... } diff --git a/.github/workflows/PlatformioBuild.yml b/.github/workflows/PlatformioBuild.yml index b6635b5a..f7552653 100644 --- a/.github/workflows/PlatformioBuild.yml +++ b/.github/workflows/PlatformioBuild.yml @@ -36,6 +36,8 @@ jobs: - m5unified - s3box - m5stack-atom + - m5stack-cores3 + - sdfat-test platform-version: #- 1.0.6 @@ -45,9 +47,10 @@ jobs: #- 2.0.3 #- 2.0.4 #- 2.0.5 - - 2.0.6 + #- 2.0.6 - 2.0.7 - 2.0.8 + - 2.0.9 #exclude: #- { piocontext: s3box, platform-version: 1.0.6 } @@ -64,7 +67,7 @@ jobs: - piocontext: m5stack-core2 - piocontext: m5unified - piocontext: s3box - - { platform-version: 2.0.8, piocontext: sdfat-test } + - piocontext: sdfat-test fail-fast: false @@ -101,7 +104,9 @@ jobs: - name: Run PlatformIO run: | cd ${{ env.PROJECT_DIR }} + export pio_ver=${{ matrix.platform-version }} + export pio_env="${pio_ver//./_}" [[ "${{ env.BRANCH_NAME }}" == "master" ]] && rm dev_lib_deps.ini || echo "Develop!" && pio system prune -f - pio pkg install -e ${{ matrix.piocontext }}@${{ matrix.platform-version }} --no-save --library file://$(realpath ../../../) - pio run -e ${{ matrix.piocontext }}@${{ matrix.platform-version }} + pio pkg install -e ${{ matrix.piocontext }}-$pio_env --no-save --library file://$(realpath ../../../) + pio run -e ${{ matrix.piocontext }}-$pio_env diff --git a/examples/Headless/Headless.ino b/examples/Headless/Headless.ino index edaffcb9..240409bd 100644 --- a/examples/Headless/Headless.ino +++ b/examples/Headless/Headless.ino @@ -1,9 +1,10 @@ #define SDU_APP_NAME "Headless Example" #define SDU_APP_PATH "/Headless_Example.bin" #define SDU_NO_AUTODETECT // don't load gfx clutter (but implement my own action trigger) -#define TFCARD_CS_PIN 4 // this is needed by SD.begin() -#include // /!\ headless mode skips autodetect and may require to include the filesystem library **before** the M5StackUpdater library -#include // optional: https://github.com/tobozo/ESP32-targz +#define SDU_NO_PRAGMAS // don't print pragma messages when compiling +#define TFCARD_CS_PIN 4 // this is needed by SD.begin() +#include // /!\ headless mode skips autodetect and may require to include the filesystem library **before** the M5StackUpdater library +#include // optional: https://github.com/tobozo/ESP32-targz #include @@ -40,12 +41,9 @@ void setup() ); Serial.println("Starting application"); - - } void loop() { - } diff --git a/examples/M5Stack-SD-Menu/bootloader-tinyuf2.bin b/examples/M5Stack-SD-Menu/bootloader-tinyuf2.bin new file mode 100644 index 00000000..01e82101 Binary files /dev/null and b/examples/M5Stack-SD-Menu/bootloader-tinyuf2.bin differ diff --git a/examples/M5Stack-SD-Menu/certificates.h b/examples/M5Stack-SD-Menu/certificates.h index a1b26c93..ff2aa798 100644 --- a/examples/M5Stack-SD-Menu/certificates.h +++ b/examples/M5Stack-SD-Menu/certificates.h @@ -1,3 +1,7 @@ +#pragma once + +#if defined USE_DOWNLOADER + /* ssl_host="phpsecure.info" && \ @@ -166,3 +170,5 @@ const char* phpsecu_re_ca =\ "KOqkqm57TH2H3eDJAkSnh6/DNFu0Qg==\n"\ "-----END CERTIFICATE-----\n"\ ""; + +#endif diff --git a/examples/M5Stack-SD-Menu/controls.h b/examples/M5Stack-SD-Menu/controls.h index 23f48a23..997567d5 100644 --- a/examples/M5Stack-SD-Menu/controls.h +++ b/examples/M5Stack-SD-Menu/controls.h @@ -25,12 +25,12 @@ unsigned long beforeRepeatDelay = LONG_DELAY_BEFORE_REPEAT; bool JOY_X_pressed = false; #endif -#if defined ARDUINO_M5Stack_Core_ESP32 || defined ARDUINO_M5STACK_FIRE +#if !defined __M5UNIFIED_HPP__ && (defined ARDUINO_M5Stack_Core_ESP32 || ARDUINO_M5STACK_CORE_ESP32 || defined ARDUINO_M5STACK_FIRE) #define CAN_I_HAZ_M5FACES #endif -#if defined ARDUINO_M5STACK_Core2 +#if defined ARDUINO_M5STACK_Core2 && defined _CHIMERA_CORE_ // enable M5Core2's haptic feedback ! static bool isVibrating = false; @@ -295,7 +295,7 @@ HIDSignal getControls() } } - #if defined ARDUINO_M5Stack_Core_ESP32 || defined ARDUINO_M5STACK_FIRE || defined ARDUINO_M5STACK_Core2 || defined ARDUINO_ESP32_S3_BOX + #if defined ARDUINO_M5Stack_Core_ESP32 || defined ARDUINO_M5STACK_FIRE || defined ARDUINO_M5STACK_Core2 || defined ARDUINO_ESP32_S3_BOX || defined ARDUINO_M5STACK_CORES3 M5.update(); diff --git a/examples/M5Stack-SD-Menu/core.h b/examples/M5Stack-SD-Menu/core.h index 83fe7f19..24457379 100644 --- a/examples/M5Stack-SD-Menu/core.h +++ b/examples/M5Stack-SD-Menu/core.h @@ -1,14 +1,35 @@ #pragma once +//#include #include + +#define ECC_NO_PRAGMAS // turn ESP32-Chimera-Core's pragma messages off +#define ECC_NO_SCREENSHOT // comment this out to take screenshots +#define ECC_NO_SPEAKER // comment this out to use audio +#define ECC_NO_NVSUTILS +#define ECC_NO_POWER +#define ECC_NO_MPU +#define ECC_NO_RTC #include // use LGFX display autodetect -#include // optional: https://github.com/tobozo/ESP32-targz +//#include + +#include // optional: https://github.com/tobozo/ESP32-targz +#define SDU_NO_PRAGMAS // turn M5StackUpdater's pragma messages off #define SDU_APP_NAME "Application Launcher" -#include // https://github.com/tobozo/M5Stack-SD-Updater #if defined(ARDUINO_M5STACK_ATOM_AND_TFCARD) + #if defined _CLK && defined _MISO && defined _MOSI + #if !defined SDU_SPI_MODE + #define SDU_SPI_MODE SPI_MODE3 + #endif + #if !defined SDU_SPI_FREQ + #define SDU_SPI_FREQ 80000000 + #endif + #define SDU_SD_BEGIN [](int csPin)->bool{ SPI.begin(_CLK, _MISO, _MOSI, csPin); SPI.setDataMode(SDU_SPI_MODE); return SD.begin(csPin, SPI, SDU_SPI_FREQ); } + #endif + class LGFX_8BIT_CVBS : public lgfx::LGFX_Device { public: @@ -40,14 +61,19 @@ static LGFX_8BIT_CVBS tft; +#elif defined __M5UNIFIED_HPP__ + + M5GFX &tft( M5.Lcd ); + #else M5Display &tft( M5.Lcd ); #endif +#include // https://github.com/tobozo/M5Stack-SD-Updater -static LGFX_Sprite sprite = LGFX_Sprite( &tft ); +static SDU_Sprite sprite = SDU_Sprite( &tft ); fs::SDFS &M5_FS(SD); -void progressBar( LGFX* tft, int x, int y, int w, int h, uint8_t val, uint16_t color = 0x09F1, uint16_t bgcolor = 0x0000 ); +void progressBar( SDU_DISPLAY_TYPE tft, int x, int y, int w, int h, uint8_t val, uint16_t color = 0x09F1, uint16_t bgcolor = 0x0000 ); diff --git a/examples/M5Stack-SD-Menu/main/main.cpp b/examples/M5Stack-SD-Menu/main/main.cpp index 602bb0f3..0e96a567 100644 --- a/examples/M5Stack-SD-Menu/main/main.cpp +++ b/examples/M5Stack-SD-Menu/main/main.cpp @@ -3,6 +3,11 @@ void setup() { + + #if defined __M5UNIFIED_HPP__ + M5.Log.setEnableColor(m5::log_target_serial, false); + #endif + #ifdef ARDUINO_M5STACK_FIRE spicommon_periph_free( VSPI_HOST ); // fix 2.0.4 psramInit mess #endif diff --git a/examples/M5Stack-SD-Menu/menu.h b/examples/M5Stack-SD-Menu/menu.h index bc7bb920..da5414b6 100644 --- a/examples/M5Stack-SD-Menu/menu.h +++ b/examples/M5Stack-SD-Menu/menu.h @@ -35,39 +35,43 @@ // TODO: moved USE_DOWNLOADER features to "AppStore.ino" // auto-select board #if defined( ARDUINO_M5STACK_Core2 ) - #warning M5STACK Core2 DETECTED !! + #pragma message "M5STACK Core2 detected" #define PLATFORM_NAME "M5Core2" #define DEFAULT_REGISTRY_BOARD "m5core2" //#define USE_DOWNLOADER #elif defined( ARDUINO_M5Stack_Core_ESP32 ) - #warning M5STACK CLASSIC DETECTED !! + #pragma message "M5STACK CLASSIC detected" #define PLATFORM_NAME "M5Stack" #define DEFAULT_REGISTRY_BOARD "m5stack" //#define USE_DOWNLOADER // moved to AppStore.ino #elif defined( ARDUINO_M5STACK_FIRE ) - #warning M5STACK FIRE DETECTED !! + #pragma message "M5STACK FIRE detected" #define PLATFORM_NAME "M5Fire" #define DEFAULT_REGISTRY_BOARD "m5fire" //#define USE_DOWNLOADER #elif defined( ARDUINO_ODROID_ESP32 ) - #warning ODROID DETECTED !! + #pragma message "ODROID detected" #define PLATFORM_NAME "Odroid-GO" #define DEFAULT_REGISTRY_BOARD "odroid" #elif defined ( ARDUINO_ESP32_DEV ) || defined( ARDUINO_LOLIN_D32_PRO ) - #warning WROVER OR LOLIN_D32_PRO DETECTED !! + #pragma message "WROVER OR LOLIN_D32_PRO detected" #define DEFAULT_REGISTRY_BOARD "esp32" #define PLATFORM_NAME "ESP32" //#define USE_DOWNLOADER #elif defined( ARDUINO_ESP32_S3_BOX ) - #warning ESP32_S3_BOX DETECTED !! + #pragma message "ESP32_S3_BOX detected" #define DEFAULT_REGISTRY_BOARD "esp32s3" #define PLATFORM_NAME "S3Box" +#elif defined ARDUINO_M5STACK_CORES3 + #pragma message "M5Sack CoreS3 detected" + #define DEFAULT_REGISTRY_BOARD "cores3" + #define PLATFORM_NAME "CoreS3" #elif defined( ARDUINO_M5STACK_ATOM_AND_TFCARD ) - #warning M5Stack ATOM DETECTED !! + #pragma message "M5Stack ATOM detected" #define DEFAULT_REGISTRY_BOARD "m5atom" #define PLATFORM_NAME "M5 ATOM(matrix/lite)" #else - #warning NOTHING DETECTED !! + #pragma message "NOTHING detected" #define DEFAULT_REGISTRY_BOARD "lambda" #define PLATFORM_NAME "LAMBDA" #endif @@ -117,7 +121,7 @@ #include "compile_time.h" //#include -#if defined(_CHIMERA_CORE_) || defined(ARDUINO_M5STACK_ATOM_AND_TFCARD) +#if defined(_CHIMERA_CORE_) || defined(ARDUINO_M5STACK_ATOM_AND_TFCARD) || __has_include("lgfx/utility/lgfx_qrcode.h") #include "lgfx/utility/lgfx_qrcode.h" #define qrcode_getBufferSize lgfx_qrcode_getBufferSize #define qrcode_initText lgfx_qrcode_initText @@ -179,9 +183,9 @@ void freeMeta(); void renderIcon( FileInfo &fileInfo ); void renderMeta( JSONMeta &jsonMeta ); //void qrRender( String text, float sizeinpixels, int xOffset=-1, int yOffset=-1 ); -void qrRender( LGFX* gfx, String text, int posX, int posY, uint32_t width, uint32_t height ); +void qrRender( SDU_DISPLAY_TYPE gfx, String text, int posX, int posY, uint32_t width, uint32_t height ); -void progressBar(LGFX* tft, int x, int y, int w, int h, uint8_t val, uint16_t color, uint16_t bgcolor) +void progressBar(SDU_DISPLAY_TYPE tft, int x, int y, int w, int h, uint8_t val, uint16_t color, uint16_t bgcolor) { tft->drawRect(x, y, w, h, color); if (val > 100) val = 100; @@ -351,12 +355,12 @@ void renderMeta( JSONMeta &jsonMeta ) sprite.print( jsonMeta.authorName ); sprite.println( AUTHOR_SUFFIX ); sprite.println(); - qrRender( (LGFX*)&tft, jsonMeta.projectURL, 155, 45, 150, 150 ); + qrRender( SDU_DISPLAY_OBJ_PTR, jsonMeta.projectURL, 155, 45, 150, 150 ); } else if( jsonMeta.projectURL!="" ) { // only projectURL log_d("Rendering QRCode"); sprite.println( jsonMeta.projectURL ); sprite.println(); - qrRender( (LGFX*)&tft, jsonMeta.projectURL, 155, 45, 150, 150 ); + qrRender( SDU_DISPLAY_OBJ_PTR, jsonMeta.projectURL, 155, 45, 150, 150 ); } else { // only authorName log_d("Rendering Authorname"); sprite.println( jsonMeta.authorName ); @@ -394,7 +398,7 @@ uint8_t getLowestQRVersionFromString( String text, uint8_t ecc ) } -void qrRender( LGFX* gfx, String text, int posX, int posY, uint32_t width, uint32_t height ) +void qrRender( SDU_DISPLAY_TYPE gfx, String text, int posX, int posY, uint32_t width, uint32_t height ) { // see https://github.com/Kongduino/M5_QR_Code/blob/master/M5_QRCode_Test.ino // Create the QR code @@ -460,7 +464,7 @@ void listDir( fs::FS &fs, const char * dirName, uint8_t levels, bool process ) getFileInfo( fileInfo[appsCount], &file ); if( appsCountProgress > 0 ) { float progressRatio = ((((float)appsCount+1.0) / (float)appsCountProgress) * 80.00)+20.00; - progressBar( (LGFX*)&tft, 110, 112, 100, 20, progressRatio); + progressBar( SDU_DISPLAY_OBJ_PTR, 110, 112, 100, 20, progressRatio); tft.fillRect( 0, 140, tft.width(), 16, TFT_BLACK); tft.drawString( fileInfo[appsCount].displayName(), 160, 148, 2); } @@ -488,7 +492,7 @@ void listDir( fs::FS &fs, const char * dirName, uint8_t levels, bool process ) getFileInfo( fileInfo[appsCount], &file ); if( appsCountProgress > 0 ) { float progressRatio = ((((float)appsCount+1.0) / (float)appsCountProgress) * 80.00)+20.00; - progressBar( (LGFX*)&tft, 110, 112, 100, 20, progressRatio); + progressBar( SDU_DISPLAY_OBJ_PTR, 110, 112, 100, 20, progressRatio); tft.fillRect( 0, 140, tft.width(), 16, TFT_BLACK); tft.drawString( fileInfo[appsCount].displayName(), 160, 148, 2); } @@ -829,6 +833,8 @@ void UISetup() heapState(); + //lsPart(); + tft.setBrightness(100); lastcheck = millis(); tft.drawJpg(disk01_jpg, 1775, (tft.width()-30)/2, 100); @@ -843,7 +849,7 @@ void UISetup() #ifdef _CHIMERA_CORE_ while( !M5.sd_begin() ) #else - while( !M5_FS.begin() ) + while( !M5_FS.begin(4) ) #endif { // TODO: make a more fancy animation @@ -912,6 +918,14 @@ void UISetup() gotoSleep(); } #endif + + //Serial.println("Going to factory in 5s"); + //delay(5000); + //loadFactory(); + //ESP.restart(); + + + } @@ -927,7 +941,7 @@ void doFSChecks() checkMenuStickyPartition(); tft.fillRect(110, 112, 100, 20,0); - progressBar( (LGFX*)&tft, 110, 112, 100, 20, 10); + progressBar( SDU_DISPLAY_OBJ_PTR, 110, 112, 100, 20, 10); scanDataFolder(); // do SD / SPIFFS health checks @@ -957,7 +971,7 @@ void doFSInventory() tft.setTextColor( TFT_WHITE ); tft.setTextSize( 1 ); tft.clear(); - progressBar( (LGFX*)&tft, 110, 112, 100, 20, 20); + progressBar( SDU_DISPLAY_OBJ_PTR, 110, 112, 100, 20, 20); appsCount = 0; listDir(M5_FS, "/", 0, false); // count valid files first so a progress meter can be displayed appsCountProgress = appsCount; @@ -987,7 +1001,7 @@ void HIDMenuObserve() { tft.setBrightness( brightness ); } switch( hidState ) { - #ifdef _CHIMERA_CORE_ + #if defined _CHIMERA_CORE_ && defined USE_SCREENSHOTS case HID_SCREENSHOT: M5.ScreenShot->snap( "screenshot" ); break; diff --git a/examples/M5Stack-SD-Menu/partition_manager.h b/examples/M5Stack-SD-Menu/partition_manager.h index 56556092..5da76030 100644 --- a/examples/M5Stack-SD-Menu/partition_manager.h +++ b/examples/M5Stack-SD-Menu/partition_manager.h @@ -28,6 +28,8 @@ * */ +#include "esp_partition.h" + /* static esp_image_metadata_t getSketchMeta( const esp_partition_t* running ) { esp_image_metadata_t data; @@ -154,7 +156,7 @@ bool copyPartition(File* fs, const esp_partition_t* dst, const esp_partition_t* progress = 100 * offset / length; if (progressOld != progress) { progressOld = progress; - progressBar( (LGFX*)&tft, 110, 112, 100, 20, progress); + progressBar( SDU_DISPLAY_OBJ_PTR, 110, 112, 100, 20, progress); } } return true; @@ -180,56 +182,65 @@ void copyPartition( const char* binfilename = PROGMEM {MENU_BIN} ) } -#if defined ESP_PARTITION_TYPE_ANY - struct digest_t { - String toString( uint8_t dig[32] ) { - static String digest; - digest = ""; - char hex[3] = {0}; - for(int i=0;i<32;i++) { - snprintf( hex, 3, "%02x", dig[i] ); - digest += String(hex); - } - return digest; +struct digest_t { + String str{"0000000000000000000000000000000000000000000000000000000000000000"}; + const char* toString( uint8_t dig[32] ) + { + str = ""; + char hex[3] = {0}; + for(int i=0;i<32;i++) { + snprintf( hex, 3, "%02x", dig[i] ); + str += String(hex); } - } ; - - digest_t digest; -#endif + return str.c_str(); + } +}; void lsPart() { - #if defined ESP_PARTITION_TYPE_ANY - esp_partition_iterator_t pi = esp_partition_find(ESP_PARTITION_TYPE_ANY, ESP_PARTITION_SUBTYPE_ANY, NULL); - log_w("Partition Type Subtype Address PartSize ImgSize Digest"); - log_w("---------+------+---------+----------+----------+---------+--------"); - while(pi != NULL) { - const esp_partition_t* part = esp_partition_get(pi); - esp_image_metadata_t meta; - bool isOta = (part->label[3]=='1' || part->label[3] == '0'); - if( isOta ) meta = SDUpdater::getSketchMeta( part ); - log_w("%-8s 0x%02x 0x%02x 0x%06x %8d %8s %s", - String( part->label ), - part->type, - part->subtype, - part->address, - part->size, - isOta ? String(meta.image_len) : "n/a", - isOta ? digest.toString(meta.image_digest).c_str() : "n/a" - ); - pi = esp_partition_next( pi ); - } - esp_partition_iterator_release(pi); - #endif + esp_partition_iterator_t pi = esp_partition_find(ESP_PARTITION_TYPE_ANY, ESP_PARTITION_SUBTYPE_ANY, NULL); + log_w("Partition Type Subtype Address PartSize ImgSize Info Digest"); + log_w("---------+------+---------+----------+----------+---------+--------+--------"); + while(pi != NULL) { + const esp_partition_t* part = esp_partition_get(pi); + esp_image_metadata_t meta = esp_image_metadata_t(); + digest_t digest; + bool isFactory = part->type==ESP_PARTITION_TYPE_APP && part->subtype==ESP_PARTITION_SUBTYPE_APP_FACTORY; + bool isOta = part->type==ESP_PARTITION_TYPE_APP && (part->subtype>=ESP_PARTITION_SUBTYPE_APP_OTA_MIN && part->subtypelabel[3]=='1' || part->label[3] == '0'); + String OTAName = "OTA"; + if( isOta || isFactory ) { + meta = SDUpdater::getSketchMeta( part ); + OTAName += String( part->subtype-ESP_PARTITION_SUBTYPE_APP_OTA_MIN ); + }/* else if( isFactory ) { + if( esp_partition_get_sha256(part, meta.image_digest) != ESP_OK ) { + log_e("Bad sha"); + memset( meta.image_digest, 0, sizeof( meta.image_digest ) ); + } + }*/ + log_w("%-8s 0x%02x 0x%02x 0x%06x %8d %8s %8s %8s", + String( part->label ), + part->type, + part->subtype, + part->address, + part->size, + meta.image_len>0 ? String(meta.image_len) : "n/a", + isOta ? OTAName.c_str() : isFactory ? "Factory" : "n/a", + (isOta || isFactory) /*&& meta.image_len>0*/ ? digest.toString(meta.image_digest) : "" + ); + pi = esp_partition_next( pi ); + } + esp_partition_iterator_release(pi); } // from https://github.com/lovyan03/M5Stack_LovyanLauncher void checkMenuStickyPartition( const char* menubinfilename = PROGMEM {MENU_BIN} ) { - const esp_partition_t* running = esp_ota_get_running_partition(); - const esp_partition_t* nextupdate = esp_ota_get_next_update_partition(NULL); + const esp_partition_t* running = esp_ota_get_running_partition(); + const esp_partition_t* nextupdate = esp_ota_get_next_update_partition(NULL); + //const esp_partition_t* factorypart = SDUpdater::getFactoryPartition(); if (!running) { log_e( "Can't fetch running partition info !!" ); @@ -242,14 +253,23 @@ void checkMenuStickyPartition( const char* menubinfilename = PROGMEM {MENU_BIN} lsPart(); - //const char* menubinfilename PROGMEM {MENU_BIN} ; + size_t sksize = ESP.getSketchSize(); tft.setTextDatum(MC_DATUM); tft.setCursor(0,0); + + // if a factory partition exists, propagate there + if( SDUpdater::saveSketchToFactory() ) { + SDUpdater::loadFactory(); // should trigger a restart + log_e("Switching to factory app failed :-("); + } + + // no factory partition found (or propagation failed), try OTA0/OTA1 and propagate to SD + if (!nextupdate) { // tft.setTextFont(4); tft.print("! WARNING !\r\nNo OTA partition.\r\nCan't use SD-Updater."); delay(3000); - } else if (running && running->label[3] == '0' && nextupdate->label[3] == '1') { + } else if( running->subtype==ESP_PARTITION_SUBTYPE_APP_OTA_MIN && nextupdate->subtype==ESP_PARTITION_SUBTYPE_APP_OTA_MIN+1) { // OTA0 was flashed and OTA1 is the next in range tft.drawString("Checking 'app0' partition", 160, 10, 2); size_t sksize = ESP.getSketchSize(); if (!comparePartition(running, nextupdate, sksize)) { @@ -264,10 +284,15 @@ void checkMenuStickyPartition( const char* menubinfilename = PROGMEM {MENU_BIN} if (copyPartition( flgSD ? &dst : NULL, nextupdate, running, sksize)) { tft.drawString("Done", 160, 52, 2); } + if (flgSD) dst.close(); + } else { + log_d("Running partition and nextupdate partition match, no propagation needed"); } + SDUpdater::updateNVS(); tft.drawString("Hot-loading 'app1' partition", 160, 66, 2); + if (Update.canRollBack()) { Update.rollBack(); ESP.restart(); diff --git a/examples/M5Stack-SD-Menu/partitions_16MB_4_or_6_apps.csv b/examples/M5Stack-SD-Menu/partitions_16MB_4_or_6_apps.csv new file mode 100644 index 00000000..25a7e178 --- /dev/null +++ b/examples/M5Stack-SD-Menu/partitions_16MB_4_or_6_apps.csv @@ -0,0 +1,27 @@ +## 4 Apps + Factory +## Name, Type, SubType, Offset, Size +#nvs, data, nvs, 0x9000, 0x5000 +#otadata, data, ota, 0xe000, 0x2000 +#ota_0, 0, ota_0, 0x10000, 0x300000 +#ota_1, 0, ota_1, 0x310000, 0x300000 +#ota_2, 0, ota_2, 0x610000, 0x300000 +#ota_3, 0, ota_3, 0x910000, 0x300000 +#firmware, app, factory, 0xC10000, 0x0F0000 +#spiffs, data, spiffs, 0xD00000, 0x2F0000 +#coredump, data, coredump, 0xFF0000, 0x10000 + + + +# 6 Apps + Factory +# Name, Type, SubType, Offset, Size +nvs, data, nvs, 0x9000, 0x5000 +otadata, data, ota, 0xe000, 0x2000 +ota_0, 0, ota_0, 0x10000, 0x200000 +ota_1, 0, ota_1, 0x210000, 0x200000 +ota_2, 0, ota_2, 0x410000, 0x200000 +ota_3, 0, ota_3, 0x610000, 0x200000 +ota_4, 0, ota_4, 0x810000, 0x200000 +ota_5, 0, ota_5, 0xA10000, 0x200000 +firmware, app, factory, 0xC10000, 0x0F0000 +spiffs, data, spiffs, 0xD00000, 0x2F0000 +coredump, data, coredump, 0xFF0000, 0x10000 diff --git a/examples/M5Stack-SD-Menu/partitions_16MB_8apps.csv b/examples/M5Stack-SD-Menu/partitions_16MB_8apps.csv new file mode 100644 index 00000000..e8206915 --- /dev/null +++ b/examples/M5Stack-SD-Menu/partitions_16MB_8apps.csv @@ -0,0 +1,34 @@ +# 4 Apps + Factory +# Name, Type, SubType, Offset, Size +nvs, data, nvs, 0x9000, 0x5000 +otadata, data, ota, 0xe000, 0x2000 +ota_0, 0, ota_0, 0x10000, 0x300000 +ota_1, 0, ota_1, 0x310000, 0x300000 +ota_2, 0, ota_2, 0x610000, 0x300000 +ota_3, 0, ota_3, 0x910000, 0x300000 +firmware, app, factory, 0xC10000, 0x0F0000 +spiffs, data, spiffs, 0xD00000, 0x2F0000 +coredump, data, coredump, 0xFF0000, 0x10000 + +# 6 Apps + Factory +# Name, Type, SubType, Offset, Size +nvs, data, nvs, 0x9000, 0x5000 +otadata, data, ota, 0xe000, 0x2000 +ota_0, 0, ota_0, 0x10000, 0x200000 +ota_1, 0, ota_1, 0x210000, 0x200000 +ota_2, 0, ota_2, 0x410000, 0x200000 +ota_3, 0, ota_3, 0x610000, 0x200000 +ota_4, 0, ota_4, 0x810000, 0x200000 +ota_5, 0, ota_5, 0xA10000, 0x200000 +firmware, app, factory, 0xC10000, 0x0F0000 +spiffs, data, spiffs, 0xD00000, 0x2F0000 +coredump, data, coredump, 0xFF0000, 0x10000 + +# Based on default_16MB.csv: +## Name, Type, SubType, Offset, Size, Flags +#nvs, data, nvs, 0x9000, 0x5000, +#otadata, data, ota, 0xe000, 0x2000, +#app0, app, ota_0, 0x10000, 0x640000, +#app1, app, ota_1, 0x650000,0x640000, +#spiffs, data, spiffs, 0xc90000,0x360000, +#coredump, data, coredump,0xFF0000,0x10000, diff --git a/examples/M5Stack-SD-Menu/tinyuf2.bin b/examples/M5Stack-SD-Menu/tinyuf2.bin new file mode 100644 index 00000000..5f9d486d Binary files /dev/null and b/examples/M5Stack-SD-Menu/tinyuf2.bin differ diff --git a/examples/MultiFS/MultiFS.ino b/examples/MultiFS/MultiFS.ino new file mode 100644 index 00000000..255ef534 --- /dev/null +++ b/examples/MultiFS/MultiFS.ino @@ -0,0 +1,56 @@ + +/* +#include +#include +#include +#include +#include +#include +#include */ + +#define SDU_NO_AUTODETECT // Disable SDUpdater autodetect: this prevents to be auto-selected, however it also disables board detection + + +#define SDU_USE_SDFATFS // Tell M5StackUpdater to load and wrap SdFat32 into fs::FS::SdFat32FSImpl +#define SDU_USE_SD +#define SDU_USE_SD_MMC +#define SDU_USE_SPIFFS +#define SDU_USE_FFAT +#define SDU_USE_LITTLEFS +#define SDU_ENABLE_GZ + +#include + +SdFs sd; +auto SdFatSPIConfig = SdSpiConfig( TFCARD_CS_PIN, SHARED_SPI, SD_SCK_MHZ(25) ); + +void setup() +{ + Serial.begin(115200); + + SDUpdater sdUpdater; + + bool has_littlefs = ConfigManager::hasFS( &sdUpdater, LittleFS ); + bool has_spiffs = ConfigManager::hasFS( &sdUpdater, SPIFFS ); + bool has_sd = ConfigManager::hasFS( &sdUpdater, SD ); + bool has_sd_mmc = ConfigManager::hasFS( &sdUpdater, SD_MMC ); + bool has_ffat = ConfigManager::hasFS( &sdUpdater, FFat ); + bool has_sdfat = ConfigManager::hasFS( &sdUpdater, *ConfigManager::SDU_SdFatFsPtr ); + + + Serial.printf("Has littlefs:\t%s\nHas spiffs:\t%s\nHas sd: \t%s\nHas sd_mmc:\t%s\nHas ffat:\t%s\nHas sdfat:\t%s\n", + has_littlefs?"true":"false", + has_spiffs ?"true":"false", + has_sd ?"true":"false", + has_sd_mmc ?"true":"false", + has_ffat ?"true":"false", + has_sdfat ?"true":"false" + ); + + +} + +void loop() +{ + +} diff --git a/examples/SdFatUpdater/SdFatUpdater.ino b/examples/SdFatUpdater/SdFatUpdater.ino index 7370f3d7..ca259684 100644 --- a/examples/SdFatUpdater/SdFatUpdater.ino +++ b/examples/SdFatUpdater/SdFatUpdater.ino @@ -11,7 +11,7 @@ // M5StackUpdater library configuration #define SDU_NO_PRAGMAS // don't spawn pragma messages during compilation -#define SDU_ENABLE_GZ // auto-load ESP32-targz (will be loaded otherwise is previously included) +#define SDU_ENABLE_GZ // auto-load ESP32-targz (implicit if ESP32-targz.h is included before M5StackUpdater.h) //#include // optional gzipped firmware support, overriden by SDU_ENABLE_GZ -> https://github.com/tobozo/ESP32-targz #define SDU_NO_AUTODETECT // Disable SDUpdater autodetect: this prevents to be auto-selected, however it also disables board detection #define USE_SDFATFS // Tell M5StackUpdater to load and wrap SdFat32 into fs::FS::SdFat32FSImpl diff --git a/examples/Test/build_test/main/main.cpp b/examples/Test/build_test/main/main.cpp index e7921a7a..d001006a 100644 --- a/examples/Test/build_test/main/main.cpp +++ b/examples/Test/build_test/main/main.cpp @@ -11,7 +11,7 @@ #include "../../../M5Stack-SDLoader-Snippet/M5Stack-SDLoader-Snippet.ino" #elif defined TEST_M5StickC #include "../../../M5StickC-SPIFFS-Loader-Snippet/M5StickC-SPIFFS-Loader-Snippet.ino" -#elif defined TEST_M5Unified +#elif defined TEST_M5Unified || defined TestM5CoreS3 || defined ARDUINO_M5STACK_ATOM_AND_TFCARD #include "../../../M5Unified/M5Unified.ino" #elif defined TEST_SdFat #include "../../../SdFatUpdater/SdFatUpdater.ino" diff --git a/examples/Test/build_test/platformio.ini b/examples/Test/build_test/platformio.ini index d0ffb254..fb1bf14f 100644 --- a/examples/Test/build_test/platformio.ini +++ b/examples/Test/build_test/platformio.ini @@ -44,6 +44,10 @@ platform_packages = framework-arduinoespressif32 @ https://github.com/espressif/ platform = https://github.com/tasmota/platform-espressif32 platform_packages = framework-arduinoespressif32 @ https://github.com/espressif/arduino-esp32/releases/download/2.0.8/esp32-2.0.8.zip +[esp32_2_0_9] +platform = https://github.com/tasmota/platform-espressif32 +platform_packages = framework-arduinoespressif32 @ https://github.com/espressif/arduino-esp32/releases/download/2.0.9/esp32-2.0.9.zip + [lib_sdupdater] lib_deps = @@ -86,6 +90,8 @@ lib_deps = [lib_m5gfx] lib_deps = + SPI + SD ${lib_sdupdater.lib_deps} M5GFX Button2 @@ -124,6 +130,11 @@ build_flags = -DTEST_M5Unified board = esp32dev extends = lib_sdfatupdater build_flags = -DTEST_SdFat +lib_deps = + SdFat + M5Unified + M5Stack-SD-Updater + ESP32-targz@^1.1.8 [S3Box] @@ -135,7 +146,7 @@ board_build.f_flash = 80000000L build_flags = -DTEST_S3Box [M5AtomLite] -extends = lib_m5gfx +extends = lib_m5gfx, lib_m5unified board = m5stack-atom board_build.partitions = min_spiffs.csv build_flags = @@ -145,6 +156,22 @@ build_flags = -D _MISO=33 -D _CLK=23 +[M5CoreS3] +extends = lib_m5unified +platform = espressif32 @ 6.2.0 +board = esp32-s3-devkitc-1 +board_upload.flash_size = 16MB +board_upload.maximum_size = 16777216 +board_build.partitions = default_16MB.csv +board_build.arduino.memory_type = qio_qspi +build_flags = + ${env.build_flags} + -DARDUINO_M5STACK_CORES3 + -DBOARD_HAS_PSRAM + -DARDUINO_UDB_MODE=1 + -DTestM5CoreS3 + +[enf:sdfat-test] [env:m5stack-core-esp32] [env:m5stack-core2] [env:m5stick-c] @@ -153,79 +180,103 @@ build_flags = [env:s3box] [env:m5stack-atom] [env:sdfat-test] +[env:m5stack-cores3] -[env:sdfat-test@2.0.8] -board = esp32dev -lib_deps = - SdFat - M5Unified - M5Stack-SD-Updater - ESP32-targz@^1.1.8 -build_flags = -DTEST_SdFat +[env:sdfat-test-2_0_7] +board = esp32dev +extends = esp32_2_0_7, M5Unifier-SdFat +[env:sdfat-test-2_0_8] +board = esp32dev extends = esp32_2_0_8, M5Unifier-SdFat +[env:sdfat-test-2_0_9] +board = esp32dev +extends = esp32_2_0_9, M5Unifier-SdFat -; [env:m5stack-atom@2.0.5] -; extends = esp32_2_0_5, M5Stack -[env:m5stack-atom@2.0.6] -extends = esp32_2_0_6, M5Stack -[env:m5stack-atom@2.0.7] -extends = esp32_2_0_7, M5Stack -[env:m5stack-atom@2.0.8] -extends = esp32_2_0_8, M5Stack +[env:m5stack-cores3-2_0_6] +extends = esp32_2_0_6, M5CoreS3 +[env:m5stack-cores3-2_0_7] +extends = esp32_2_0_7, M5CoreS3 +[env:m5stack-cores3-2_0_8] +extends = esp32_2_0_8, M5CoreS3 +[env:m5stack-cores3-2_0_9] +extends = esp32_2_0_9, M5CoreS3 -; [env:m5stack-core-esp32@2.0.5] +; [env:m5stack-atom-2.0.5] +; extends = esp32_2_0_5, M5Stack +[env:m5stack-atom-2_0_6] +extends = esp32_2_0_6, M5AtomLite +[env:m5stack-atom-2_0_7] +extends = esp32_2_0_7, M5AtomLite +[env:m5stack-atom-2_0_8] +extends = esp32_2_0_8, M5AtomLite +[env:m5stack-atom-2_0_9] +extends = esp32_2_0_9, M5AtomLite + +; [env:m5stack-core-esp32-2.0.5] ; extends = esp32_2_0_5, M5Stack -[env:m5stack-core-esp32@2.0.6] +[env:m5stack-core-esp32-2_0_6] extends = esp32_2_0_6, M5Stack -[env:m5stack-core-esp32@2.0.7] +[env:m5stack-core-esp32-2_0_7] extends = esp32_2_0_7, M5Stack -[env:m5stack-core-esp32@2.0.8] +[env:m5stack-core-esp32-2_0_8] extends = esp32_2_0_8, M5Stack +[env:m5stack-core-esp32-2_0_9] +extends = esp32_2_0_9, M5Stack -; [env:m5stack-core2@2.0.5] +; [env:m5stack-core2-2.0.5] ; extends = esp32_2_0_5, M5Core2 -[env:m5stack-core2@2.0.6] +[env:m5stack-core2-2_0_6] extends = esp32_2_0_6, M5Core2 -[env:m5stack-core2@2.0.7] +[env:m5stack-core2-2_0_7] extends = esp32_2_0_7, M5Core2 -[env:m5stack-core2@2.0.8] +[env:m5stack-core2-2_0_8] extends = esp32_2_0_8, M5Core2 +[env:m5stack-core2-2_0_9] +extends = esp32_2_0_9, M5Core2 -; [env:m5stick-c@2.0.5] +; [env:m5stick-c-2.0.5] ; extends = esp32_2_0_5, M5StickC -[env:m5stick-c@2.0.6] +[env:m5stick-c-2_0_6] extends = esp32_2_0_6, M5StickC -[env:m5stick-c@2.0.7] +[env:m5stick-c-2_0_7] extends = esp32_2_0_7, M5StickC -[env:m5stick-c@2.0.8] +[env:m5stick-c-2_0_8] extends = esp32_2_0_8, M5StickC +[env:m5stick-c-2_0_9] +extends = esp32_2_0_9, M5StickC -; [env:m5unified@2.0.5] +; [env:m5unified-2.0.5] ; extends = esp32_2_0_5, M5Unified -[env:m5unified@2.0.6] +[env:m5unified-2_0_6] extends = esp32_2_0_6, M5Unified -[env:m5unified@2.0.7] +[env:m5unified-2_0_7] extends = esp32_2_0_7, M5Unified -[env:m5unified@2.0.8] +[env:m5unified-2_0_8] extends = esp32_2_0_8, M5Unified +[env:m5unified-2_0_9] +extends = esp32_2_0_9, M5Unified -; [env:lgfx@2.0.5] +; [env:lgfx-2.0.5] ; extends = esp32_2_0_5, lgfx -[env:lgfx@2.0.6] +[env:lgfx-2_0_6] extends = esp32_2_0_6, lgfx -[env:lgfx@2.0.7] +[env:lgfx-2_0_7] extends = esp32_2_0_7, lgfx -[env:lgfx@2.0.8] +[env:lgfx-2_0_8] extends = esp32_2_0_8, lgfx +[env:lgfx-2_0_9] +extends = esp32_2_0_9, lgfx -; [env:s3box@2.0.5] +; [env:s3box-2.0.5] ; extends = esp32_2_0_5, S3Box -[env:s3box@2.0.6] +[env:s3box-2_0_6] extends = esp32_2_0_6, S3Box -[env:s3box@2.0.7] +[env:s3box-2_0_7] extends = esp32_2_0_7, S3Box -[env:s3box@2.0.8] +[env:s3box-2_0_8] extends = esp32_2_0_8, S3Box +[env:s3box-2_0_9] +extends = esp32_2_0_9, S3Box diff --git a/library.json b/library.json index d9567538..75dde2dc 100644 --- a/library.json +++ b/library.json @@ -16,7 +16,7 @@ "version": ">=1.1.7" } ], - "version": "1.2.5", + "version": "1.2.7", "framework": "arduino", "headers": "M5StackUpdater.h", "platforms": "espressif32" diff --git a/library.properties b/library.properties index d1375101..ab954b07 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=M5Stack-SD-Updater -version=1.2.5 +version=1.2.7 author=tobozo maintainer=tobozo sentence=SD Card Loader for M5 Stack diff --git a/src/ConfigManager/ConfigManager.hpp b/src/ConfigManager/ConfigManager.hpp index ae5accd1..006f41b7 100644 --- a/src/ConfigManager/ConfigManager.hpp +++ b/src/ConfigManager/ConfigManager.hpp @@ -47,20 +47,22 @@ namespace SDUpdaterNS bool S3MuteButtonChanged(); #endif - typedef bool (*fsCheckerCb)( SDUpdater* sdu, fs::FS &fs, bool report_errors ); extern void setup(); extern bool hasFS( SDUpdater *sdu, fs::FS &fs, bool report_errors ); - // interface to UpdateClass, may pass through GzUpdateClass - extern UpdateInterfaceNS::UpdateManagerInterface_t Iface; + extern UpdateInterfaceNS::UpdateManagerInterface_t *GetUpdateInterface(); + + using namespace UpdateInterfaceNS; // SDUpdater config callbacks and params struct config_sdu_t { config_sdu_t(); fs::FS *fs = nullptr; + //FS_Config_t *fsConfig = nullptr; bool mounted = false; + bool fs_begun = false; void *display = nullptr; // dereferenced display object void* getCompilationTimeDisplay(); void* getRunTimeDisplay(); diff --git a/src/FS/ffat.hpp b/src/FS/ffat.hpp new file mode 100644 index 00000000..66ef0dc2 --- /dev/null +++ b/src/FS/ffat.hpp @@ -0,0 +1,52 @@ +#pragma once + +#if defined SDU_HAS_FFAT + + #include "../misc/config.h" + #include "../misc/types.h" + #include + + namespace SDUpdaterNS + { + + namespace ConfigManager + { + struct FFat_FS_Config_t + { + bool formatOnFail{false}; + const char * basePath{"/ffat"}; + uint8_t maxOpenFiles{10}; + const char * partitionLabel{FFAT_PARTITION_LABEL}; + }; + + static FFat_FS_Config_t *FFat_ConfigPtr = nullptr; + static fs::FS *SDU_FFat_Ptr = &FFat; + }; + + inline ConfigManager::FFat_FS_Config_t* SDU_FFat_CONFIG_GET() + { + if( ConfigManager::FFat_ConfigPtr ) return ConfigManager::FFat_ConfigPtr; + static ConfigManager::FFat_FS_Config_t FFat_Config = ConfigManager::FFat_FS_Config_t(); + ConfigManager::FFat_ConfigPtr = &FFat_Config; + return ConfigManager::FFat_ConfigPtr; + } + + #define SDU_CONFIG_FFat *SDU_FFat_CONFIG_GET() + + inline ConfigManager::FS_Config_t* SDU_FFAT_GET() + { + static ConfigManager::FS_Config_t FFat_FS_Config = {"ffat", ConfigManager::SDU_FFat_Ptr, ConfigManager::FFat_ConfigPtr}; + return &FFat_FS_Config; + } + + + inline bool SDU_FFat_Begin(ConfigManager::FFat_FS_Config_t cfg=ConfigManager::FFat_FS_Config_t()) + { + ConfigManager::FFat_ConfigPtr = &cfg; + return FFat.begin( cfg.formatOnFail, cfg.basePath, cfg.maxOpenFiles, cfg.partitionLabel ); + } + + + }; + +#endif diff --git a/src/FS/littlefs.hpp b/src/FS/littlefs.hpp new file mode 100644 index 00000000..668bbb35 --- /dev/null +++ b/src/FS/littlefs.hpp @@ -0,0 +1,53 @@ +#pragma once + +#if defined SDU_HAS_LITTLEFS + + #include "../misc/config.h" + #include "../misc/types.h" + #include + + namespace SDUpdaterNS + { + + namespace ConfigManager + { + struct LittleFS_FS_Config_t + { + bool formatOnFail{false}; + const char * basePath{"/littlefs"}; + uint8_t maxOpenFiles{10}; + const char * partitionLabel{"spiffs"}; + }; + static LittleFS_FS_Config_t *LittleFS_ConfigPtr = nullptr; + static fs::FS *SDU_LittleFS_Ptr = &LittleFS; + }; + + + inline ConfigManager::LittleFS_FS_Config_t* SDU_LittleFS_CONFIG_GET() + { + if( ConfigManager::LittleFS_ConfigPtr ) return ConfigManager::LittleFS_ConfigPtr; + static ConfigManager::LittleFS_FS_Config_t LittleFS_Config = ConfigManager::LittleFS_FS_Config_t(); + ConfigManager::LittleFS_ConfigPtr = &LittleFS_Config; + return ConfigManager::LittleFS_ConfigPtr; + } + + #define SDU_CONFIG_LittleFS *SDU_LittleFS_CONFIG_GET() + + + inline ConfigManager::FS_Config_t* SDU_LITTLEFS_GET() + { + static ConfigManager::FS_Config_t LittleFS_FS_Config = {"littlefs", ConfigManager::SDU_LittleFS_Ptr, ConfigManager::LittleFS_ConfigPtr}; + return &LittleFS_FS_Config; + } + + + inline bool SDU_LittleFS_Begin(ConfigManager::LittleFS_FS_Config_t cfg=ConfigManager::LittleFS_FS_Config_t()) + { + ConfigManager::LittleFS_ConfigPtr = &cfg; + return LittleFS.begin( cfg.formatOnFail, cfg.basePath, cfg.maxOpenFiles, cfg.partitionLabel ); + } + + + }; + +#endif diff --git a/src/FS/sd.hpp b/src/FS/sd.hpp new file mode 100644 index 00000000..efe0c491 --- /dev/null +++ b/src/FS/sd.hpp @@ -0,0 +1,59 @@ +#pragma once + +#if defined SDU_HAS_SD + + #include "../misc/config.h" + #include "../misc/types.h" + #include + + namespace SDUpdaterNS + { + + namespace ConfigManager + { + struct SD_FS_Config_t + { + uint8_t csPin{TFCARD_CS_PIN}; + SPIClass *bus{&SPI}; + uint32_t freq{4000000}; + }; + static SD_FS_Config_t *SD_ConfigPtr = nullptr; + static fs::FS *SDU_SD_Ptr = &SD; + }; + + + inline ConfigManager::SD_FS_Config_t* SDU_SD_CONFIG_GET() + { + if( ConfigManager::SD_ConfigPtr ) return ConfigManager::SD_ConfigPtr; + static ConfigManager::SD_FS_Config_t SD_Config = ConfigManager::SD_FS_Config_t(); + ConfigManager::SD_ConfigPtr = &SD_Config; + return ConfigManager::SD_ConfigPtr; + } + + #define SDU_CONFIG_SD *SDU_SD_CONFIG_GET() + + + inline ConfigManager::FS_Config_t* SDU_SD_GET() + { + static ConfigManager::FS_Config_t SD_FS_Config = {"sd", ConfigManager::SDU_SD_Ptr, ConfigManager::SD_ConfigPtr}; + return &SD_FS_Config; + } + + + inline bool SDU_SDBegin( uint8_t csPin ) + { + return SD.begin( csPin ); + } + + inline bool SDU_SDBegin( ConfigManager::SD_FS_Config_t cfg=ConfigManager::SD_FS_Config_t() ) + { + ConfigManager::SD_ConfigPtr = &cfg; + return cfg.bus ? SD.begin(cfg.csPin, *cfg.bus, cfg.freq) : SD.begin(cfg.csPin); + } + + + }; + +#endif + + diff --git a/src/FS/sd_mmc.hpp b/src/FS/sd_mmc.hpp new file mode 100644 index 00000000..c83dc344 --- /dev/null +++ b/src/FS/sd_mmc.hpp @@ -0,0 +1,71 @@ +#pragma once + +#if defined SDU_HAS_SD_MMC + + #include "../misc/config.h" + #include "../misc/types.h" + #include + + namespace SDUpdaterNS + { + + namespace ConfigManager + { + struct SD_MMC_Bus_Config_t + { + int freq{BOARD_MAX_SDMMC_FREQ}; + int clk{-1}; + int cmd{-1}; + int d0{-1}; + int d1{-1}; + int d2{-1}; + int d3{-1}; + }; + struct SD_MMC_FS_Config_t + { + const char * mountpoint{"/sdcard"}; + bool mode1bit{false}; + bool format_if_mount_failed{false}; + SD_MMC_Bus_Config_t busCfg{SD_MMC_Bus_Config_t()}; + uint8_t maxOpenFiles{5}; + }; + static SD_MMC_FS_Config_t *SD_MMC_ConfigPtr = nullptr; + static fs::FS *SDU_SD_MMC_Ptr = &SD_MMC; + }; + + + inline ConfigManager::SD_MMC_FS_Config_t* SDU_SD_MMC_CONFIG_GET() + { + if( ConfigManager::SD_MMC_ConfigPtr ) return ConfigManager::SD_MMC_ConfigPtr; + static ConfigManager::SD_MMC_FS_Config_t SD_MMC_Config = ConfigManager::SD_MMC_FS_Config_t(); + ConfigManager::SD_MMC_ConfigPtr = &SD_MMC_Config; + return ConfigManager::SD_MMC_ConfigPtr; + } + + #define SDU_CONFIG_SD_MMC *SDU_SD_MMC_CONFIG_GET() + + + inline ConfigManager::FS_Config_t* SDU_SD_MMC_GET() + { + static ConfigManager::FS_Config_t SD_MMC_FS_Config = {"sdmmc", ConfigManager::SDU_SD_MMC_Ptr, ConfigManager::SD_MMC_ConfigPtr}; + return &SD_MMC_FS_Config; + } + + + inline bool SDU_SD_MMC_Begin( ConfigManager::SD_MMC_FS_Config_t cfg=ConfigManager::SD_MMC_FS_Config_t() ) + { + auto busCfg = cfg.busCfg; + if( busCfg.clk!=-1 && busCfg.cmd!=-1 && busCfg.d0!=-1 ) { + if( busCfg.d1!=-1 && busCfg.d2!=-1 && busCfg.d3!=-1 ) { + SD_MMC.setPins( busCfg.clk, busCfg.cmd, busCfg.d0, busCfg.d1, busCfg.d2, busCfg.d3 ); + } else { + SD_MMC.setPins( busCfg.clk, busCfg.cmd, busCfg.d0 ); + } + } + ConfigManager::SD_MMC_ConfigPtr = &cfg; + return SD_MMC.begin(cfg.mountpoint, cfg.mode1bit, cfg.format_if_mount_failed, cfg.busCfg.freq, cfg.maxOpenFiles); + } + + }; + +#endif diff --git a/src/misc/sdfat32fs_wrapper.hpp b/src/FS/sdfat.hpp similarity index 89% rename from src/misc/sdfat32fs_wrapper.hpp rename to src/FS/sdfat.hpp index 873ffc6a..7a824c8d 100644 --- a/src/misc/sdfat32fs_wrapper.hpp +++ b/src/FS/sdfat.hpp @@ -4,7 +4,7 @@ // Inspired by @ockernuts https://github.com/ockernuts // See https://github.com/greiman/SdFat/issues/148#issuecomment-1464448806 -#if defined USE_SDFATFS +#if defined SDU_HAS_SDFS #if !defined SDFAT_FILE_TYPE #define SDFAT_FILE_TYPE 3 // tell SdFat.h to support all filesystem types (fat16/fat32/ExFat) @@ -13,12 +13,14 @@ #error "SD Updater only supports SdFs" #endif - #undef __has_include + #include "../misc/config.h" + #include "../misc/types.h" + + #undef __has_include // tell SdFat to define 'File' object needed to convert access mode to flag #include #include #include - #define __has_include(STR) __has_include__(STR) - + #define __has_include(STR) __has_include__(STR) // kudos to @GOB52 for this trick // cfr https://en.cppreference.com/w/c/io/fopen + guesses inline oflag_t _convert_access_mode_to_flag(const char* mode, const bool create = false) @@ -123,7 +125,17 @@ return &_fs; } - inline bool SDU_SDFatBegin( SdSpiConfig *SdFatCfg ) + + inline ConfigManager::FS_Config_t* SDU_SDFAT_GET() + { + static ConfigManager::FS_Config_t SDFAT_FS_Config = {"sdfat", ConfigManager::SDU_SdFatPtr, ConfigManager::SDU_SdSpiConfigPtr}; + return &SDFAT_FS_Config; + } + + //#define SDU_CONFIG_SDFAT ConfigManager::SDU_SdSpiConfigPtr + + + inline bool SDU_SDFat_Begin( SdSpiConfig *SdFatCfg ) { using namespace ConfigManager; if( !SDU_SdFatPtr ) { diff --git a/src/FS/spiffs.hpp b/src/FS/spiffs.hpp new file mode 100644 index 00000000..c36bf693 --- /dev/null +++ b/src/FS/spiffs.hpp @@ -0,0 +1,56 @@ +#pragma once + +#if defined SDU_HAS_SPIFFS + + #include "../misc/config.h" + #include "../misc/types.h" + #include + + namespace SDUpdaterNS + { + + namespace ConfigManager + { + struct SPIFFS_FS_Config_t + { + bool formatOnFail{false}; + const char * basePath{"/spiffs"}; + uint8_t maxOpenFiles{10}; + const char * partitionLabel{NULL}; + }; + + static SPIFFS_FS_Config_t *SPIFFS_ConfigPtr = nullptr; + static fs::FS *SDU_SPIFFS_Ptr = &SPIFFS; + + }; + + inline ConfigManager::SPIFFS_FS_Config_t* SDU_SPIFFS_CONFIG_GET() + { + if( ConfigManager::SPIFFS_ConfigPtr ) return ConfigManager::SPIFFS_ConfigPtr; + static ConfigManager::SPIFFS_FS_Config_t SPIFFS_Config = ConfigManager::SPIFFS_FS_Config_t(); + ConfigManager::SPIFFS_ConfigPtr = &SPIFFS_Config; + return ConfigManager::SPIFFS_ConfigPtr; + } + + #define SDU_CONFIG_SPIFFS *SDU_SPIFFS_CONFIG_GET() + + + inline ConfigManager::FS_Config_t* SDU_SPIFFS_GET() + { + static ConfigManager::FS_Config_t SPIFFS_FS_Config = {"spiffs", ConfigManager::SDU_SPIFFS_Ptr, ConfigManager::SPIFFS_ConfigPtr}; + return &SPIFFS_FS_Config; + } + + + inline bool SDU_SPIFFS_Begin(ConfigManager::SPIFFS_FS_Config_t cfg=ConfigManager::SPIFFS_FS_Config_t()) + { + ConfigManager::SPIFFS_ConfigPtr = &cfg; + return SPIFFS.begin( cfg.formatOnFail, cfg.basePath, cfg.maxOpenFiles, cfg.partitionLabel ); + } + + }; + +#endif + + + diff --git a/src/M5StackUpdater.hpp b/src/M5StackUpdater.hpp index 32047caf..2b883738 100644 --- a/src/M5StackUpdater.hpp +++ b/src/M5StackUpdater.hpp @@ -87,6 +87,7 @@ #include "gitTagVersion.h" #include "./misc/assets.h" +#include "./misc/config.h" #include "./misc/types.h" #include #include @@ -94,7 +95,7 @@ #define resetReason (int)rtc_get_reset_reason(0) -// use `#define SDU_NO_PRAGMAS` to disable pragma messages +// use `#define SDU_NO_PRAGMAS` to disable duplicate pragma messages #if !defined SDU_NO_PRAGMAS #define SDU_STRINGIFY(a) #a #define SDU_PRAGMA_MESSAGE(msg) \ @@ -105,59 +106,72 @@ // inherit filesystem includes from sketch -#if defined _SD_H_ + +#if defined _SD_H_ || defined SDU_USE_SD #define SDU_HAS_SD - #if defined _CLK && defined _MISO && defined _MOSI - // user provided specific pinout via build extra flags - #if !defined SDU_SPI_MODE - #define SDU_SPI_MODE SPI_MODE3 - #endif - #if !defined SDU_SPI_FREQ - #define SDU_SPI_FREQ 80000000 - #endif - SDU_PRAGMA_MESSAGE("SD has custom SPI pins") - #define SDU_SD_BEGIN [](int csPin)->bool{ SPI.begin(_CLK, _MISO, _MOSI, csPin); SPI.setDataMode(SDU_SPI_MODE); return SD.begin(csPin, SPI, SDU_SPI_FREQ); } - #else - #define SDU_SD_BEGIN(csPin) SD.begin(csPin) + #include "./FS/sd.hpp" + #if !defined SDU_BEGIN_SD + #define SDU_BEGIN_SD SDU_SDBegin #endif #endif -#if defined _SDMMC_H_ +#if defined _SDMMC_H_ || defined SDU_USE_SD_MMC #define SDU_HAS_SD_MMC - /*#include */ + #include "./FS/sd_mmc.hpp" + #if !defined SDU_BEGIN_SD_MMC + #define SDU_BEGIN_SD_MMC SDU_SD_MMC_Begin + #endif #endif -#if defined _SPIFFS_H_ +#if defined _SPIFFS_H_ || defined SDU_USE_SPIFFS #define SDU_HAS_SPIFFS - /*#include */ + #include "./FS/spiffs.hpp" + #if !defined SDU_BEGIN_SPIFFS + #define SDU_BEGIN_SPIFFS SDU_SPIFFS_Begin + #endif +#endif + +#if defined _FFAT_H_ || defined SDU_USE_FFAT + #define SDU_HAS_FFAT + #include "./FS/ffat.hpp" + #if !defined SDU_BEGIN_FFat + #define SDU_BEGIN_FFat SDU_FFat_Begin + #endif #endif -#if defined _LiffleFS_H_ || __has_include() +#if defined _LiffleFS_H_ || defined SDU_USE_LITTLEFS #define SDU_HAS_LITTLEFS - #include + #include "./FS/littlefs.hpp" + #if !defined SDU_BEGIN_LittleFS + #define SDU_BEGIN_LittleFS SDU_LittleFS_Begin + #endif #endif -#if __has_include() || defined _LIFFLEFS_H_ +#if defined _LIFFLEFS_H_ || __has_include() // LittleFS is now part of esp32 package, the older, external version isn't supported #warning "Older version of is unsupported and will be ignored" #warning "Use builtin version with #include instead, if using platformio add LittleFS(esp32)@^2.0.0 to lib_deps" #endif // Note: SdFat can't be detected using __has_include() without creating problems downstream in the code. -// Until this is solved, enabling SdFat is done by adding `#defined USE_SDFATFS` to the sketch before including the library. -#if defined USE_SDFATFS +// Until this is solved, enabling SdFat is done by adding `#defined SDU_USE_SDFATFS` to the sketch before including the library. +#if defined SDU_USE_SDFATFS || defined USE_SDFATFS #define SDU_HAS_SDFS SDU_PRAGMA_MESSAGE("SDUpdater will use SdFat") - #include "./misc/sdfat32fs_wrapper.hpp" - #define SDU_SDFS_BEGIN SDU_SDFatBegin + #include "./FS/sdfat.hpp" + #if !defined SDU_BEGIN_SDFat + #define SDU_BEGIN_SDFat SDU_SDFat_Begin + #endif #endif -#if !defined SDU_HAS_SD && !defined SDU_HAS_SD_MMC && !defined SDU_HAS_SPIFFS && !defined SDU_HAS_LITTLEFS && !defined SDU_HAS_SDFS +#if !defined SDU_HAS_SD && !defined SDU_HAS_SD_MMC && !defined SDU_HAS_SPIFFS && !defined SDU_HAS_LITTLEFS && !defined SDU_HAS_SDFS && !defined SDU_HAS_FFAT SDU_PRAGMA_MESSAGE("SDUpdater didn't detect any preselected filesystem, will use SD as default") #define SDU_HAS_SD - #include - #define SDU_SD_BEGIN(csPin) SD.begin(csPin) + #include "./FS/sd.hpp" + #if !defined SDU_BEGIN_SD + #define SDU_BEGIN_SD SDU_SDBegin + #endif #endif #if defined SDU_ENABLE_GZ || defined _ESP_TGZ_H || __has_include() @@ -183,7 +197,7 @@ #define SDU_TouchButton LGFX_Button #define HAS_LGFX // ESP32-Chimera-Core creates the HAS_TOUCH macro when the selected display supports it - #if !defined SDU_HAS_TOUCH && /*ARDUINO_M5STACK_Core2 ||*/ defined HAS_TOUCH + #if !defined SDU_HAS_TOUCH && defined HAS_TOUCH #define SDU_HAS_TOUCH #endif #elif defined _M5STACK_H_ @@ -198,6 +212,13 @@ #define SDU_DISPLAY_OBJ_PTR &M5.Lcd #define SDU_TouchButton TFT_eSPI_Button #define SDU_HAS_TOUCH // M5Core2 has implicitely enabled touch interface + #elif defined _M5CORES3_H_ + SDU_PRAGMA_MESSAGE("M5Core3.h detected") + #define SDU_Sprite TFT_eSprite + #define SDU_DISPLAY_TYPE M5Display* + #define SDU_DISPLAY_OBJ_PTR &M5.Lcd + #define SDU_TouchButton TFT_eSPI_Button + #define SDU_HAS_TOUCH // M5Core3 has implicitely enabled touch interface #elif defined _M5STICKC_H_ SDU_PRAGMA_MESSAGE("M5StickC.h detected") #define SDU_Sprite TFT_eSprite @@ -210,15 +231,17 @@ #define SDU_DISPLAY_OBJ_PTR &M5.Display #define SDU_TouchButton LGFX_Button #define HAS_LGFX - #if !defined SDU_HAS_TOUCH && defined ARDUINO_M5STACK_Core2 + #if !defined SDU_HAS_TOUCH && (defined ARDUINO_M5STACK_Core2 || defined ARDUINO_M5STACK_CORE2 || defined ARDUINO_M5STACK_CORES3 ) #define SDU_HAS_TOUCH #endif #else - SDU_PRAGMA_MESSAGE(message "No display driver detected") + #if defined SDU_USE_DISPLAY + SDU_PRAGMA_MESSAGE(message "No display driver detected") + #undef SDU_USE_DISPLAY + #endif #define SDU_DISPLAY_OBJ_PTR nullptr //#define SDU_DISPLAY_TYPE void* //#define SDU_Sprite void* - #undef SDU_USE_DISPLAY #undef HAS_M5_API #endif #endif @@ -235,7 +258,7 @@ #endif #else // SDUpdater will use Serial as trigger source - #if !defined SDU_NO_AUTODETECT + #if !defined SDU_NO_AUTODETECT && !defined SDU_HEADLESS SDU_PRAGMA_MESSAGE(message "No M5 API found") #endif #define DEFAULT_BTN_POLLER nullptr @@ -258,22 +281,21 @@ #endif #endif -// load the SDUpdater stack -#include "./misc/update_interface.hpp" +// now that all the contextual flags are created, load the SDUpdater stack #include "./ConfigManager/ConfigManager.hpp" +#include "./SDUpdater/Update_Interface.hpp" #include "./SDUpdater/SDUpdater_Class.hpp" #include "./UI/common.hpp" -// load the lobby and button decorations if applicable -#if defined SDU_USE_DISPLAY +#if defined SDU_USE_DISPLAY // load the lobby and button decorations if applicable SDU_PRAGMA_MESSAGE("Attached UI") - #define SDU_GFX ((SDU_DISPLAY_TYPE)(SDUCfg.display)) // macro for UI.hpp + #define SDU_GFX ((SDU_DISPLAY_TYPE)(SDUCfg.display)) // type-casted display macro for UI.hpp #include "./UI/UI.hpp" - #if defined SDU_HAS_TOUCH // load touch helpers + #if defined SDU_HAS_TOUCH // load touch helpers if applicable SDU_PRAGMA_MESSAGE("Attached Touch support") #include "./UI/Touch.hpp" #endif -#else // bind unknown display to SDUCfg.display, whatever it is... +#else // bind null display to SDUCfg.display #define SDU_GFX ((void*)(SDUCfg.display)) // macro for UI.hpp #endif @@ -303,21 +325,21 @@ namespace SDUpdaterNS { using namespace TriggerSource; using namespace SDU_UI; - triggers = new triggerMap_t( SDU_TRIGGER_TOUCHBUTTON, labelMenu, labelSkip, labelRollback, triggerInitTouch, triggerActionTouch, triggerFinalizeTouch ); + SDUCfg.triggers = new triggerMap_t( SDU_TRIGGER_TOUCHBUTTON, labelMenu, labelSkip, labelRollback, triggerInitTouch, triggerActionTouch, triggerFinalizeTouch ); } inline void config_sdu_t::useBuiltinPushButton() { using namespace TriggerSource; using namespace SDU_UI; - triggers = new triggerMap_t( SDU_TRIGGER_PUSHBUTTON, labelMenu, labelSkip, labelRollback, triggerInitButton, triggerActionButton, triggerFinalizeButton ); + SDUCfg.triggers = new triggerMap_t( SDU_TRIGGER_PUSHBUTTON, labelMenu, labelSkip, labelRollback, triggerInitButton, triggerActionButton, triggerFinalizeButton ); } inline void config_sdu_t::useBuiltinSerial() { using namespace TriggerSource; using namespace SDU_UI; - triggers = new TriggerSource::triggerMap_t( SDU_TRIGGER_SERIAL, labelMenu, labelSkip, labelRollback, triggerInitSerial, triggerActionSerial, triggerFinalizeSerial ); + SDUCfg.triggers = new TriggerSource::triggerMap_t( SDU_TRIGGER_SERIAL, labelMenu, labelSkip, labelRollback, triggerInitSerial, triggerActionSerial, triggerFinalizeSerial ); } @@ -335,7 +357,6 @@ namespace SDUpdaterNS if( !Buttons[1].cb ) setBtnB( FN_LAMBDA_BOOL(DEFAULT_BTNB_CHECKER) ); if( !Buttons[2].cb ) setBtnC( FN_LAMBDA_BOOL(DEFAULT_BTNC_CHECKER) ); - if( !labelMenu && LAUNCHER_LABEL ) labelMenu = LAUNCHER_LABEL; if( !labelSkip && SKIP_LABEL ) labelSkip = SKIP_LABEL; if( !labelRollback && ROLLBACK_LABEL ) labelRollback = ROLLBACK_LABEL; @@ -404,64 +425,45 @@ namespace SDUpdaterNS } - inline bool hasFS( SDUpdater* sdu, fs::FS &fs, bool report_errors ) + + // logic block generator for hasFS() filesystem detection/init + #define SD_MOUNT_ANY_FS_IF( cond, begin_cb, name ) \ + if( cond ) { \ + if( !begin_cb ){ \ + msg[0] = name " MOUNT FAILED"; \ + if( report_errors ) sdu->_error( msg, 2 ); \ + return false; \ + } else { log_d("%s Successfully mounted", name); } \ + mounted = true; \ + } \ + + // function call generator to SD_MOUNT_ANY_FS_IF( condition, begin-callback, filesystem-name ) + #define SD_MOUNT_FS_IF( fsobj ) SD_MOUNT_ANY_FS_IF( &fs == &fsobj, SDU_BEGIN_##fsobj (SDU_CONFIG_##fsobj ), #fsobj ); + + inline bool hasFS( SDUpdater* sdu, fs::FS &fs, bool report_errors=true ) { assert(sdu); bool mounted = sdu->cfg->mounted; // inherit config mount state as default (can be triggered by rollback) const char* msg[] = {nullptr, "ABORTING"}; - #if defined _SPIFFS_H_ - if( &fs == &SPIFFS ) { - if( !SPIFFS.begin() ){ - msg[0] = "SPIFFS MOUNT FAILED"; - if( report_errors ) sdu->_error( msg, 2 ); - return false; - } else { log_d("SPIFFS Successfully mounted"); } - mounted = true; - } + #if defined SDU_HAS_SPIFFS // _SPIFFS_H_ + SD_MOUNT_FS_IF( SPIFFS ); #endif - #if defined (_LITTLEFS_H_) - if( &fs == &LittleFS ) { - if( !LittleFS.begin() ){ - msg[0] = "LittleFS MOUNT FAILED"; - if( report_errors ) sdu->_error( msg, 2 ); - return false; - } else { log_d("LittleFS Successfully mounted"); } - mounted = true; - } + #if defined SDU_HAS_LITTLEFS // _LITTLEFS_H_ + SD_MOUNT_FS_IF( LittleFS ); #endif - #if defined (_SD_H_) - if( &fs == &SD ) { - if( ! SDU_SD_BEGIN(sdu->cfg->TFCardCsPin) ) { - msg[0] = String("SD MOUNT FAILED (pin #" + String(sdu->cfg->TFCardCsPin) + ")").c_str(); - if( report_errors ) sdu->_error( msg, 2 ); - return false; - } else { - log_d("[%d] SD Successfully mounted (pin #%d)", ESP.getFreeHeap(), sdu->cfg->TFCardCsPin ); - } - mounted = true; - } + #if defined SDU_HAS_FFAT //_FFAT_H_ + SD_MOUNT_FS_IF( FFat ); #endif - #if defined (_SDMMC_H_) - if( &fs == &SD_MMC ) { - if( !SD_MMC.begin() ){ - msg[0] = "SD_MMC FAILED"; - if( report_errors ) sdu->_error( msg, 2 ); - return false; - } else { log_d( "SD_MMC Successfully mounted"); } - mounted = true; - } + #if defined SDU_HAS_SD // _SD_H_ + SDU_SD_CONFIG_GET()->csPin = sdu->cfg->TFCardCsPin; + SD_MOUNT_FS_IF( SD ); #endif - #if defined USE_SDFATFS - using namespace ConfigManager; - if( SDU_SdFatFsPtr ) { - if( !SDU_SDFS_BEGIN( SDU_SdSpiConfigPtr ) ) { - msg[0] = String("SDFat MOUNT FAILED ").c_str(); - if( report_errors ) sdu->_error( msg, 2 ); - return false; - } - log_d("[%d] SDFat Successfully mounted (pin #%d)", ESP.getFreeHeap(), SDU_SdSpiConfigPtr->csPin ); - mounted = true; - } + #if defined SDU_HAS_SD_MMC // _SDMMC_H_ + //SDU_SD_MMC_CONFIG_GET()->busCfg.freq = 40000000; + SD_MOUNT_FS_IF( SD_MMC ); + #endif + #if defined SDU_HAS_SDFS + SD_MOUNT_ANY_FS_IF( &fs==ConfigManager::SDU_SdFatFsPtr, SDU_BEGIN_SDFat(ConfigManager::SDU_SdSpiConfigPtr), "SDFat" ); #endif return mounted; } @@ -513,6 +515,8 @@ namespace SDUpdaterNS } + + // provide a conditional function to cover more devices, including headless and touch inline void checkSDUpdater( fs::FS &fs, String fileName, unsigned long waitdelay, const int TfCardCsPin_ ) { @@ -557,7 +561,22 @@ namespace SDUpdaterNS } - #if defined USE_SDFATFS + // inline void checkSDUpdater( ConfigManager::FS_Config_t &cfg, String fileName, unsigned long waitdelay ) + // { + // SDUCfg.fsConfig = &cfg; + // SDUpdater sdUpdater( &SDUCfg ); + // + // if( SDUCfg.display != nullptr ) { + // sdUpdater.checkSDUpdaterUI( fileName, waitdelay ); + // } else { + // if( waitdelay <=100 ) waitdelay = 2000; + // sdUpdater.checkSDUpdaterHeadless( fileName, waitdelay ); + // } + // } + + + + #if defined SDU_HAS_SDFS inline void checkSDUpdater( SdFs &sd, String fileName=MENU_BIN, unsigned long waitdelay=0, SdSpiConfig *SdFatCfg=nullptr ) { diff --git a/src/SDUpdater/SDUpdater_Class.cpp b/src/SDUpdater/SDUpdater_Class.cpp index 6bd6912a..ad6a0d2a 100644 --- a/src/SDUpdater/SDUpdater_Class.cpp +++ b/src/SDUpdater/SDUpdater_Class.cpp @@ -15,18 +15,61 @@ namespace SDUpdaterNS void SDUpdater::_error( const String& errMsg, unsigned long waitdelay ) { - Serial.print("[ERROR] "); - Serial.println( errMsg ); - if( cfg->onError ) cfg->onError( errMsg, waitdelay ); + SDU_SERIAL.print("[ERROR] "); + SDU_SERIAL.println( errMsg ); + if( SDUCfg.onError ) SDUCfg.onError( errMsg, waitdelay ); } void SDUpdater::_message( const String& msg ) { - Serial.println( msg ); - if( cfg->onMessage ) cfg->onMessage( msg ); + SDU_SERIAL.println( msg ); + if( SDUCfg.onMessage ) SDUCfg.onMessage( msg ); } + + + //*********************************************************************************************** + // B A C K T O F A C T O R Y * + //*********************************************************************************************** + // https://www.esp32.com/posting.php?mode=quote&f=2&p=19066&sid=5ba5f33d5fe650eb8a7c9f86eb5b61b8 + // Return to factory version. * + // This will set the otadata to boot from the factory image, ignoring previous OTA updates. * + //*********************************************************************************************** + void SDUpdater::loadFactory() + { + esp_partition_iterator_t pi ; // Iterator for find + const esp_partition_t* factory ; // Factory partition + esp_err_t err ; + + pi = esp_partition_find ( ESP_PARTITION_TYPE_APP, ESP_PARTITION_SUBTYPE_APP_FACTORY, NULL ) ; + + if ( pi == NULL ) { // Check result + log_e( "Failed to find factory partition" ) ; + } else { + factory = esp_partition_get ( pi ) ; // Get partition struct + esp_partition_iterator_release ( pi ) ; // Release the iterator + err = esp_ota_set_boot_partition ( factory ) ; // Set partition for boot + if ( err != ESP_OK ) { // Check error + log_e( "Failed to set boot partition" ) ; + } else { + esp_restart() ; // Restart ESP + } + } + } + + + const esp_partition_t* SDUpdater::getFactoryPartition() + { + auto factorypi = esp_partition_find ( ESP_PARTITION_TYPE_APP, ESP_PARTITION_SUBTYPE_APP_FACTORY, NULL ); + if( factorypi != NULL ) { + return esp_partition_get(factorypi); + } + return NULL; + } + + + esp_image_metadata_t SDUpdater::getSketchMeta( const esp_partition_t* source_partition ) { esp_image_metadata_t data; @@ -39,31 +82,55 @@ namespace SDUpdaterNS .size = source_partition->size, }; data.start_addr = source_partition_pos.offset; - esp_err_t ret = esp_image_verify( ESP_IMAGE_VERIFY, &source_partition_pos, &data ); - // only verify OTA0 or OTA1 - if( source_partition->label[3] == '1' || source_partition->label[3] == '0' ) { + + esp_app_desc_t app_desc; + if( esp_ota_get_partition_description(source_partition, &app_desc) != ESP_OK ) { + // nothing flashed here + memset( data.image_digest, 0, sizeof(data.image_digest) ); + data.image_len = 0; + return data; + } + + // only verify OTA partitions + if( source_partition->type==ESP_PARTITION_TYPE_APP && (source_partition->subtype>=ESP_PARTITION_SUBTYPE_APP_OTA_MIN && source_partition->subtypelabel ), source_partition->address ); } else { - //log_w("Successfully verified image %s at addr %x", String( source_partition->label[3] ), source_partition->address ); + log_v("Successfully verified image %s at addr %x", String( source_partition->label[3] ), source_partition->address ); + } + } else if( source_partition->type==ESP_PARTITION_TYPE_APP && source_partition->subtype==ESP_PARTITION_SUBTYPE_APP_FACTORY ) { + // factory partition, compute the digest + if( esp_partition_get_sha256(source_partition, data.image_digest) != ESP_OK ) { + memset( data.image_digest, 0, sizeof(data.image_digest) ); + data.image_len = 0; } } return data;//.image_len; } - /* - static void SDUpdater::getFactoryPartition() + + bool SDUpdater::compareFlashPartition(const esp_partition_t* src1, const esp_partition_t* src2, size_t length) { - esp_partition_iterator_t pi = esp_partition_find( ESP_PARTITION_TYPE_APP, ESP_PARTITION_SUBTYPE_APP_FACTORY, NULL ); - if(pi != NULL) { - const esp_partition_t* factory = esp_partition_get(pi); - esp_partition_iterator_release(pi); - if(esp_ota_set_boot_partition(factory) == ESP_OK) { - //esp_restart(); + size_t lengthLeft = length; + const size_t bufSize = SPI_FLASH_SEC_SIZE; + std::unique_ptr buf1(new uint8_t[bufSize]); + std::unique_ptr buf2(new uint8_t[bufSize]); + uint32_t offset = 0; + size_t i; + while( lengthLeft > 0) { + size_t readBytes = (lengthLeft < bufSize) ? lengthLeft : bufSize; + if (!ESP.flashRead(src1->address + offset, reinterpret_cast(buf1.get()), (readBytes + 3) & ~3) + || !ESP.flashRead(src2->address + offset, reinterpret_cast(buf2.get()), (readBytes + 3) & ~3)) { + return false; } + for (i = 0; i < readBytes; ++i) if (buf1[i] != buf2[i]) return false; + lengthLeft -= readBytes; + offset += readBytes; } + return true; } - */ + bool SDUpdater::compareFsPartition(const esp_partition_t* src1, fs::File* src2, size_t length) @@ -85,11 +152,11 @@ namespace SDUpdaterNS for (i = 0; i < readBytes; ++i) if (buf1[i] != buf2[i]) return false; lengthLeft -= readBytes; offset += readBytes; - if( cfg->onProgress ) { + if( SDUCfg.onProgress ) { progress = 100 * offset / length; if (progressOld != progress) { progressOld = progress; - cfg->onProgress( (uint8_t)progress, 100 ); + SDUCfg.onProgress( (uint8_t)progress, 100 ); } } } @@ -113,11 +180,11 @@ namespace SDUpdaterNS if (dst) dst->write(buf.get(), (readBytes + 3) & ~3); lengthLeft -= readBytes; offset += readBytes; - if( cfg->onProgress ) { + if( SDUCfg.onProgress ) { progress = 100 * offset / length; if (progressOld != progress) { progressOld = progress; - cfg->onProgress( (uint8_t)progress, 100 ); + SDUCfg.onProgress( (uint8_t)progress, 100 ); vTaskDelay(10); } } @@ -126,10 +193,82 @@ namespace SDUpdaterNS } - bool SDUpdater::saveSketchToFS( fs::FS &fs, const char* binfilename, bool skipIfExists ) + bool SDUpdater::copyFlashPartition(const esp_partition_t* dst, const esp_partition_t* src, size_t length) + { + if( dst->size < length ) { + log_e("data won't fit in destination partition (available: %d, needed: %d)", dst->size, length ); + return false; + } + + size_t lengthLeft = length; + const size_t bufSize = SPI_FLASH_SEC_SIZE; + std::unique_ptr buf(new uint8_t[bufSize]); + uint32_t offset = 0; + uint32_t progress = 0, progressOld = 0; + while( lengthLeft > 0) { + size_t readBytes = (lengthLeft < bufSize) ? lengthLeft : bufSize; + if (!ESP.flashRead(src->address + offset, reinterpret_cast(buf.get()), (readBytes + 3) & ~3) + || !ESP.flashEraseSector((dst->address + offset) / bufSize) + || !ESP.flashWrite(dst->address + offset, reinterpret_cast(buf.get()), (readBytes + 3) & ~3)) { + return false; + } + lengthLeft -= readBytes; + offset += readBytes; + if( SDUCfg.onProgress ) { + progress = 100 * offset / length; + if (progressOld != progress) { + progressOld = progress; + SDUCfg.onProgress( (uint8_t)progress, 100 ); + } + } + } + return true; + } + + + + + bool SDUpdater::saveSketchToFactory() + { + const esp_partition_t* running = esp_ota_get_running_partition(); + //const esp_partition_t* nextupdate = esp_ota_get_next_update_partition(NULL); + const esp_partition_t* factorypart = SDUpdater::getFactoryPartition(); + + if( !factorypart ) { + log_w( "This flash has no factory partition" ); + return false; + } + if (!running) { + log_e( "Can't fetch running partition info !!" ); + return false; + } + size_t sksize = ESP.getSketchSize(); + + if( running == factorypart ) { + log_d("Sketch is running from factory partition, no need to propagate"); + return false; + } + + if (!compareFlashPartition(running, factorypart, sksize)) { + if( copyFlashPartition( factorypart, running, sksize) ) { + log_d("Sketch successfully propagated to factory partition"); + return true; + } else { + log_e("Sketch propagation to factory partition failed"); + } + } else { + log_i("Current sketch and factory partition already match"); + return true; + } + return false; + } + + + + bool SDUpdater::saveSketchToFS( SDUpdater* sdu, fs::FS &fs, const char* binfilename, bool skipIfExists ) { // no rollback possible, start filesystem - if( !_fsBegin( fs ) ) { + if( !_fsBegin( sdu, fs ) ) { const char *msg[] = {"No Filesystem mounted.","Can't check firmware."}; _error( msg, 2 ); return false; @@ -142,26 +281,26 @@ namespace SDUpdaterNS return false; } } - if( cfg->onBefore) cfg->onBefore(); - if( cfg->onProgress ) cfg->onProgress( 0, 100 ); + if( SDUCfg.onBefore) SDUCfg.onBefore(); + if( SDUCfg.onProgress ) SDUCfg.onProgress( 0, 100 ); const esp_partition_t *running = esp_ota_get_running_partition(); size_t sksize = ESP.getSketchSize(); bool ret = false; fs::File dst = fs.open(binfilename, FILE_WRITE ); - if( cfg->onProgress ) cfg->onProgress( 25, 100 ); + if( SDUCfg.onProgress ) SDUCfg.onProgress( 25, 100 ); _message( String("Overwriting ") + String(binfilename) ); if (copyFsPartition( &dst, running, sksize)) { - if( cfg->onProgress ) cfg->onProgress( 75, 100 ); + if( SDUCfg.onProgress ) SDUCfg.onProgress( 75, 100 ); _message( String("Done ") + String(binfilename) ); vTaskDelay(1000); ret = true; } else { _error( "Copy failed" ); } - if( cfg->onProgress ) cfg->onProgress( 100, 100 ); + if( SDUCfg.onProgress ) SDUCfg.onProgress( 100, 100 ); dst.close(); - if( cfg->onAfter) cfg->onAfter(); + if( SDUCfg.onAfter) SDUCfg.onAfter(); return ret; } @@ -177,7 +316,7 @@ namespace SDUpdaterNS } esp_image_metadata_t nusketchMeta = getSketchMeta( update_partition ); uint32_t nuSize = nusketchMeta.image_len; - Serial.printf( "Updating menu.bin NVS size/digest after update: %d\n", nuSize ); + SDU_SERIAL.printf( "Updating menu.bin NVS size/digest after update: %d\n", nuSize ); Preferences preferences; preferences.begin( "sd-menu", false ); preferences.putInt( "menusize", nuSize ); @@ -198,26 +337,26 @@ namespace SDUpdaterNS if (UpdateIface->begin( updateSize )) { size_t written = UpdateIface->writeStream( updateSource, updateSize ); if ( written == updateSize ) { - Serial.println( "Written : " + String(written) + " successfully" ); + SDU_SERIAL.println( "Written : " + String(written) + " successfully" ); } else { - Serial.println( "Written only : " + String(written) + "/" + String(updateSize) + ". Retry?" ); + SDU_SERIAL.println( "Written only : " + String(written) + "/" + String(updateSize) + ". Retry?" ); } if ( UpdateIface->end() ) { - Serial.println( "OTA done!" ); + SDU_SERIAL.println( "OTA done!" ); if ( UpdateIface->isFinished() ) { if( strcmp( MenuBin, fileName.c_str() ) == 0 ) { // maintain NVS signature SDUpdater::updateNVS(); } - Serial.println( "Update successfully completed. Rebooting." ); + SDU_SERIAL.println( "Update successfully completed. Rebooting." ); } else { - Serial.println( "Update not finished? Something went wrong!" ); + SDU_SERIAL.println( "Update not finished? Something went wrong!" ); } } else { - Serial.println( "Update failed. Error #: " + String( UpdateIface->getError() ) ); + SDU_SERIAL.println( "Update failed. Error #: " + String( UpdateIface->getError() ) ); } } else { - Serial.println( "Not enough space to begin OTA" ); + SDU_SERIAL.println( "Not enough space to begin OTA" ); } } @@ -260,7 +399,7 @@ namespace SDUpdaterNS uint8_t image_digest[32]; preferences.getBytes( "digest", image_digest, 32 ); preferences.end(); - Serial.println( "Trying rollback" ); + SDU_SERIAL.println( "Trying rollback" ); if( menuSize == 0 ) { log_d( "Failed to get expected menu size from NVS ram, can't check if rollback is worth a try..." ); @@ -280,11 +419,11 @@ namespace SDUpdaterNS return; } - Serial.println( "Sizes match! Checking digest..." ); + SDU_SERIAL.println( "Sizes match! Checking digest..." ); bool match = true; for( uint8_t i=0; i<32; i++ ) { if( image_digest[i]!=sketchMeta.image_digest[i] ) { - Serial.println( "NO match for NVS digest :-(" ); + SDU_SERIAL.println( "NO match for NVS digest :-(" ); match = false; break; } @@ -299,7 +438,7 @@ namespace SDUpdaterNS void SDUpdater::updateFromStream( Stream &stream, size_t updateSize, const String& fileName ) { if ( updateSize > 0 ) { - Serial.println( "Try to start update" ); + SDU_SERIAL.println( "Try to start update" ); disableCore0WDT(); // disable WDT it as suggested by twitter.com/@lovyan03 performUpdate( stream, updateSize, fileName ); enableCore0WDT(); @@ -337,12 +476,12 @@ namespace SDUpdaterNS _error( msg, 2 ); return; } - Serial.printf( "[" SD_PLATFORM_NAME "-SD-Updater] SD Updater version: %s\n", (char*)M5_SD_UPDATER_VERSION ); + SDU_SERIAL.printf( "[" SD_PLATFORM_NAME "-SD-Updater] SD Updater version: %s\n", (char*)M5_SD_UPDATER_VERSION ); #ifdef M5_LIB_VERSION - Serial.printf( "[" SD_PLATFORM_NAME "-SD-Updater] M5Stack Core version: %s\n", (char*)M5_LIB_VERSION ); + SDU_SERIAL.printf( "[" SD_PLATFORM_NAME "-SD-Updater] M5Stack Core version: %s\n", (char*)M5_LIB_VERSION ); #endif - Serial.printf( "[" SD_PLATFORM_NAME "-SD-Updater] Application was Compiled on %s %s\n", __DATE__, __TIME__ ); - Serial.printf( "[" SD_PLATFORM_NAME "-SD-Updater] Will attempt to load binary %s \n", fileName.c_str() ); + SDU_SERIAL.printf( "[" SD_PLATFORM_NAME "-SD-Updater] Application was Compiled on %s %s\n", __DATE__, __TIME__ ); + SDU_SERIAL.printf( "[" SD_PLATFORM_NAME "-SD-Updater] Will attempt to load binary %s \n", fileName.c_str() ); // try rollback first, it's faster! if( strcmp( MenuBin, fileName.c_str() ) == 0 ) { @@ -354,7 +493,7 @@ namespace SDUpdaterNS } } // no rollback possible, start filesystem - if( !_fsBegin() ) { + if( !_fsBegin(this) ) { const char* msg[] = {"No filesystem mounted.", "Can't load firmware."}; _error( msg, 2 ); return; @@ -388,12 +527,12 @@ namespace SDUpdaterNS if( waitdelay == 0 ) { waitdelay = 100; // at least give some time for the serial buffer to fill } - Serial.printf("SDUpdater: you have %d milliseconds to send 'update', 'rollback', 'skip' or 'save' command\n", (int)waitdelay); + SDU_SERIAL.printf("SDUpdater: you have %d milliseconds to send 'update', 'rollback', 'skip' or 'save' command\n", (int)waitdelay); if( cfg->onWaitForAction ) { int ret = cfg->onWaitForAction( nullptr, nullptr, nullptr, waitdelay ); if ( ret == ConfigManager::SDU_BTNA_MENU ) { - Serial.printf( SDU_LOAD_TPL, fileName.c_str() ); + SDU_SERIAL.printf( SDU_LOAD_TPL, fileName.c_str() ); updateFromFS( fileName ); ESP.restart(); } @@ -405,7 +544,7 @@ namespace SDUpdaterNS _error( "Missing onWaitForAction!" ); } - Serial.println("Delay expired, no SD-Update will occur"); + SDU_SERIAL.println("Delay expired, no SD-Update will occur"); } @@ -447,11 +586,11 @@ namespace SDUpdaterNS if ( ret == ConfigManager::SDU_BTNA_MENU ) { if( isRollBack == false ) { - Serial.printf( SDU_LOAD_TPL, fileName.c_str() ); + SDU_SERIAL.printf( SDU_LOAD_TPL, fileName.c_str() ); updateFromFS( fileName ); ESP.restart(); } else { - Serial.println( SDU_ROLLBACK_MSG ); + SDU_SERIAL.println( SDU_ROLLBACK_MSG ); doRollBack( SDU_ROLLBACK_MSG ); } } diff --git a/src/SDUpdater/SDUpdater_Class.hpp b/src/SDUpdater/SDUpdater_Class.hpp index b8ba3bf9..4bbe1ffb 100644 --- a/src/SDUpdater/SDUpdater_Class.hpp +++ b/src/SDUpdater/SDUpdater_Class.hpp @@ -25,23 +25,10 @@ extern "C" { #endif #include -#include +// #include // required to store the MENU_BIN hash #include -#if !defined(TFCARD_CS_PIN) // override this from your sketch if the guess is wrong - #if defined( ARDUINO_LOLIN_D32_PRO ) || defined( ARDUINO_M5STACK_Core2 ) || defined( ARDUINO_M5Stack_Core_ESP32 ) || defined( ARDUINO_M5STACK_FIRE) - #define TFCARD_CS_PIN 4 - #elif defined( ARDUINO_ESP32_WROVER_KIT ) || defined( ARDUINO_ODROID_ESP32 ) - #define TFCARD_CS_PIN 22 - #elif defined ARDUINO_TWATCH_BASE || defined ARDUINO_TWATCH_2020_V1 || defined ARDUINO_TWATCH_2020_V2 || defined(ARDUINO_TTGO_T1) - #define TFCARD_CS_PIN 13 - #else - #define TFCARD_CS_PIN SS - #endif -#endif - - #include "../ConfigManager/ConfigManager.hpp" namespace SDUpdaterNS @@ -60,6 +47,10 @@ namespace SDUpdaterNS using ConfigManager::config_sdu_t; using UpdateInterfaceNS::UpdateManagerInterface_t; + #if !defined SDU_SERIAL + #define SDU_SERIAL Serial + #endif + class SDUpdater { public: @@ -77,13 +68,24 @@ namespace SDUpdaterNS void updateFromFS( fs::FS &fs, const String& fileName = MENU_BIN ); void updateFromStream( Stream &stream, size_t updateSize, const String& fileName ); void doRollBack( const String& message = "" ); + // flash to SD binary replication - bool compareFsPartition(const esp_partition_t* src1, fs::File* src2, size_t length); - bool copyFsPartition(fs::File* dst, const esp_partition_t* src, size_t length); - bool saveSketchToFS(fs::FS &fs, const char* binfilename = PROGMEM {MENU_BIN}, bool skipIfExists = false ); + static bool compareFsPartition(const esp_partition_t* src1, fs::File* src2, size_t length); + static bool copyFsPartition(fs::File* dst, const esp_partition_t* src, size_t length); + + static bool saveSketchToFS( SDUpdater* sdu, fs::FS &fs, const char* binfilename={MENU_BIN}, bool skipIfExists=false ); + inline bool saveSketchToFS( fs::FS &fs, const char* binfilename={MENU_BIN}, bool skipIfExists=false ) { return saveSketchToFS(this, fs, binfilename, skipIfExists ); } + // static methods static void updateNVS(); static esp_image_metadata_t getSketchMeta( const esp_partition_t* source_partition ); + static const esp_partition_t* getFactoryPartition(); + static void loadFactory(); + static bool saveSketchToFactory(); + static bool compareFlashPartition(const esp_partition_t* src1, const esp_partition_t* src2, size_t length); + static bool copyFlashPartition(const esp_partition_t* dst, const esp_partition_t* src, size_t length); + + // fs::File->name() changed behaviour after esp32 sdk 2.x.x inline static const char* fs_file_path( fs::File *file ) { @@ -94,9 +96,9 @@ namespace SDUpdaterNS #endif } - void _error( const String& errMsg, unsigned long waitdelay = 2000 ); - void _error( const char **errMsgs, uint8_t msgCount=1, unsigned long waitdelay=2000 ); - void _message( const String& label ); + static void _error( const String& errMsg, unsigned long waitdelay = 2000 ); + static void _error( const char **errMsgs, uint8_t msgCount=1, unsigned long waitdelay=2000 ); + static void _message( const String& label ); config_sdu_t* cfg; private: @@ -106,14 +108,14 @@ namespace SDUpdaterNS void performUpdate( Stream &updateSource, size_t updateSize, String fileName ); void tryRollback( String fileName ); - #if defined _M5Core2_H_ // enable additional touch button support + #if defined _M5Core2_H_ || defined _M5CORES3_H_ + // Implicitely assume touch button support for TFT_eSpi based cores as per M5.begin() default behaviour const bool SDUHasTouch = true; #else const bool SDUHasTouch = false; #endif - bool _fs_begun = false; - bool _fsBegin( bool report_errors = true ); - bool _fsBegin( fs::FS &fs, bool report_errors = true ); + static bool _fsBegin( SDUpdater* sdu, bool report_errors = true ); + static bool _fsBegin( SDUpdater* sdu, fs::FS &fs, bool report_errors = true ); }; @@ -122,7 +124,7 @@ namespace SDUpdaterNS inline SDUpdater::SDUpdater( config_sdu_t* _cfg ) : cfg(_cfg) { if( !UpdateIface ) { - UpdateIface = &ConfigManager::Iface; + UpdateIface = ConfigManager::GetUpdateInterface(); } if( ConfigManager::SDUCfgLoader ) { log_v("Config manager loader called"); @@ -130,7 +132,7 @@ namespace SDUpdaterNS } else { cfg->setDefaults(); } - _fs_begun = _fsBegin( false ); + cfg->fs_begun = _fsBegin( this, false ); }; @@ -138,7 +140,7 @@ namespace SDUpdaterNS inline SDUpdater::SDUpdater( const int TFCardCsPin_ ) { if( !UpdateIface ) { - UpdateIface = &ConfigManager::Iface; + UpdateIface = ConfigManager::GetUpdateInterface(); } //log_d("SDUpdater base mode on CS pin(%d)", TFCardCsPin_ ); SDUCfg.setCSPin( TFCardCsPin_ ); @@ -149,22 +151,22 @@ namespace SDUpdaterNS } else { cfg->setDefaults(); } - _fs_begun = _fsBegin( false ); + cfg->fs_begun = _fsBegin( this, false ); }; - inline bool SDUpdater::_fsBegin( bool report_errors ) + inline bool SDUpdater::_fsBegin( SDUpdater* sdu, bool report_errors ) { - if( cfg->fs != nullptr ) return _fsBegin( *cfg->fs, report_errors ); - if( !cfg->mounted ) _error( "No filesystem selected" ); // Note: rollback does not need filesystem + if( SDUCfg.fs != nullptr ) return _fsBegin( sdu, *SDUCfg.fs, report_errors ); + if( !SDUCfg.mounted ) _error( "No filesystem selected" ); // Note: rollback does not need filesystem return false; } - inline bool SDUpdater::_fsBegin( fs::FS &fs, bool report_errors ) + inline bool SDUpdater::_fsBegin( SDUpdater* sdu, fs::FS &fs, bool report_errors ) { - if( _fs_begun ) return true; - if( cfg->fsChecker ) return cfg->fsChecker( this, *cfg->fs, report_errors ); + if( SDUCfg.fs_begun ) return true; + if( SDUCfg.fsChecker ) return SDUCfg.fsChecker( sdu, *SDUCfg.fs, report_errors ); return false; } diff --git a/src/SDUpdater/Update_Interface.hpp b/src/SDUpdater/Update_Interface.hpp new file mode 100644 index 00000000..bd3acd0c --- /dev/null +++ b/src/SDUpdater/Update_Interface.hpp @@ -0,0 +1,68 @@ +#pragma once + + +#if defined SDU_HAS_TARGZ // binary may or may not be gzipped + + // some macros with if(gz) logic + #define GzUpdate GzUpdateClass::getInstance() + #define GzUpdateEnd() (mode_z ? GzUpdate.endgz() : GzUpdate.end()) + #define GzAbort() if (mode_z) GzUpdate.abortgz(); else GzUpdate.abort() + #define GzWriteStream(updateSource,updateSize) (mode_z ? GzUpdate.writeGzStream(updateSource,updateSize) : GzUpdate.writeStream(updateSource)) + #define GzCanBegin( usize ) (mode_z ? GzUpdate.begingz(UPDATE_SIZE_UNKNOWN) : GzUpdate.begin(usize)) + #define GzEnd() (mode_z ? GzUpdate.endgz() : GzUpdate.end() ) + + namespace SDUpdaterNS + { + namespace ConfigManager + { + using namespace UpdateInterfaceNS; + inline UpdateManagerInterface_t *GetUpdateInterface() + { + static UpdateManagerInterface_t Iface = + { + .begin = [](size_t s)->bool{ return GzCanBegin(s); }, + .writeStream = [](Stream &data,size_t size)->size_t{ return GzWriteStream(data, size); }, + .abort = [](){ GzAbort(); }, + .end = []()->bool{ return GzEnd(); }, + .isFinished = []()->bool{ return GzUpdate.isFinished(); }, + .canRollBack = []()->bool{ return GzUpdate.canRollBack(); }, + .rollBack = []()->bool{ return GzUpdate.rollBack(); }, + .onProgress = [](UpdateClass::THandlerFunction_Progress fn){ GzUpdate.onProgress(fn); }, + .getError = []()->uint8_t{ return GzUpdate.getError(); }, + .setBinName = []( String& fileName, Stream* stream ) { mode_z=fileName.endsWith(".gz")?(stream->peek()==0x1f):false; log_d("Compression %s", mode_z?"enabled":"disabled"); } + }; + return &Iface; + } + + }; + }; + +#else // no gzip support, only native firmwares + + namespace SDUpdaterNS + { + namespace ConfigManager + { + using namespace UpdateInterfaceNS; + inline UpdateManagerInterface_t *GetUpdateInterface() + { + static UpdateManagerInterface_t Iface = + { + .begin = [](size_t s)->bool{ return Update.begin(s); }, + .writeStream = [](Stream &data,size_t size)->size_t{ return Update.writeStream(data); }, + .abort = [](){ Update.abort(); }, + .end = []()->bool{ return Update.end(); }, + .isFinished = []()->bool{ return Update.isFinished(); }, + .canRollBack = []()->bool{ return Update.canRollBack(); }, + .rollBack = []()->bool{ return Update.rollBack(); }, + .onProgress = [](UpdateClass::THandlerFunction_Progress fn){ Update.onProgress(fn); }, + .getError = []()->uint8_t{ return Update.getError(); }, + .setBinName = [](String&fileName, Stream* stream) { if(fileName.endsWith(".gz")) log_e("Gz file detected but gz support is disabled!"); } + }; + return &Iface; + } + + }; + } + +#endif diff --git a/src/UI/Touch.hpp b/src/UI/Touch.hpp index 17140c1e..c4c72a65 100644 --- a/src/UI/Touch.hpp +++ b/src/UI/Touch.hpp @@ -82,15 +82,15 @@ namespace SDUpdaterNS inline TouchStyles::TouchStyles() { padx = 4; // buttons padding X - pady = 5; // buttons padding Y - marginx = 4; // buttons margin X - marginy = 4; // buttons margin Y + pady = 1; // buttons padding Y + marginx = 2; // buttons margin X + marginy = 2; // buttons margin Y x1 = marginx + SDU_GFX->width()/4; // button 1 X position x2 = marginx+SDU_GFX->width()-SDU_GFX->width()/4; // button 2 X position x3 = SDU_GFX->width()/2; // button 3 X position - y = SDU_GFX->height()/2.2; // buttons Y position + y = SDU_GFX->height()/2; // buttons Y position w = (SDU_GFX->width()/2)-(marginx*2); // buttons width - h = SDU_GFX->height()/4, // buttons height + h = SDU_GFX->height()/5, // buttons height y1 = marginx*3+SDU_GFX->height()-h; // button3 y position icon_x = marginx+12; // icon (button 1) X position icon_y = y-8; // icon (button 1) Y position @@ -278,8 +278,8 @@ namespace SDUpdaterNS auto SkipBtn = el->SkipBtn; auto SaveBtn = el->SaveBtn; - #if defined _M5Core2_H_ - // clean handlers + #if ! defined HAS_LGFX // defined _M5Core2_H_ || defined _M5CORES3_H_ + // clear TFT_eSpi button handlers LoadBtn->delHandlers(); SkipBtn->delHandlers(); SaveBtn->delHandlers(); diff --git a/src/UI/common.hpp b/src/UI/common.hpp index 3647fd63..6edaf462 100644 --- a/src/UI/common.hpp +++ b/src/UI/common.hpp @@ -2,6 +2,9 @@ #include "../misc/types.h" +#pragma GCC diagnostic ignored "-Wunused-function" +#pragma GCC diagnostic ignored "-Wunused-variable" + namespace SDUpdaterNS { @@ -174,19 +177,23 @@ namespace SDUpdaterNS static int actionTriggered( char* labelLoad, char* labelSkip, char* labelSave, unsigned long waitdelay ) { auto trigger = SDUCfg.triggers; + if( !trigger ) { log_e("No triggers assigned, aborting"); return -1; } + + trigger->waitdelay = waitdelay; + if( trigger->waitdelay == 0 ) { log_i("waitdelay=0 -> skipping action trigger detection"); return -1; } switch( trigger->source ) { - case SDU_TRIGGER_SERIAL: log_d("Listening to trigger source: Serial"); break; - case SDU_TRIGGER_PUSHBUTTON: log_d("Listening to trigger source: Push Button"); break; - case SDU_TRIGGER_TOUCHBUTTON: log_d("Listening to trigger source: Touch Button"); break; + case SDU_TRIGGER_SERIAL: log_d("Listening to trigger source: Serial, delay=%ms", trigger->waitdelay); break; + case SDU_TRIGGER_PUSHBUTTON: log_d("Listening to trigger source: Push Button, delay=%ms", trigger->waitdelay); break; + case SDU_TRIGGER_TOUCHBUTTON: log_d("Listening to trigger source: Touch Button, delay=%ms", trigger->waitdelay); break; } auto msec = millis(); int ret = -1; diff --git a/src/gitTagVersion.h b/src/gitTagVersion.h index 950dbcdb..04ac15d5 100644 --- a/src/gitTagVersion.h +++ b/src/gitTagVersion.h @@ -1,6 +1,6 @@ #define SDU_VERSION_MAJOR 1 #define SDU_VERSION_MINOR 2 -#define SDU_VERSION_PATCH 5 +#define SDU_VERSION_PATCH 7 #define _SDU_STR(x) #x #define SDU_STR(x) _SDU_STR(x) // Macro to convert library version number into an integer diff --git a/src/misc/assets.h b/src/misc/assets.h index 461b62fe..b56bf209 100644 --- a/src/misc/assets.h +++ b/src/misc/assets.h @@ -278,4 +278,3 @@ const unsigned char sdUpdaterIcon32x40_jpg[] = { }; const unsigned int sdUpdaterIcon32x40_jpg_len = 1855; -//#endif diff --git a/src/misc/config.h b/src/misc/config.h index bd452976..be463fe0 100644 --- a/src/misc/config.h +++ b/src/misc/config.h @@ -24,23 +24,25 @@ // Fancy names for detected boards -#if defined ARDUINO_M5Stick_C +#if defined ARDUINO_M5Stick_C || defined ARDUINO_M5STICK_C #define SD_PLATFORM_NAME "M5StickC" #elif defined ARDUINO_ODROID_ESP32 #define SD_PLATFORM_NAME "Odroid-GO" -#elif defined ARDUINO_M5Stack_Core_ESP32 +#elif defined ARDUINO_M5Stack_Core_ESP32 || defined ARDUINO_M5STACK_CORE_ESP32 #define SD_PLATFORM_NAME "M5Stack" #elif defined ARDUINO_M5STACK_FIRE - #define SD_PLATFORM_NAME "M5Stack-Fire" -#elif defined ARDUINO_M5STACK_Core2 - #define SD_PLATFORM_NAME "M5StackCore2" + #define SD_PLATFORM_NAME "M5Fire" +#elif defined ARDUINO_M5STACK_Core2 || defined ARDUINO_M5STACK_CORE2 + #define SD_PLATFORM_NAME "M5Core2" +#elif defined ARDUINO_M5STACK_CORES3 + #define SD_PLATFORM_NAME "M5CoreS3" #elif defined ARDUINO_ESP32_WROVER_KIT #define SD_PLATFORM_NAME "Wrover-Kit" #elif defined ARDUINO_TTGO_T1 // TTGO T1 #define SD_PLATFORM_NAME "TTGO-T1" #elif defined ARDUINO_LOLIN_D32_PRO // LoLin D32 Pro #define SD_PLATFORM_NAME "LoLin D32 Pro" -#elif defined ARDUINO_T_Watch // TWatch, all models +#elif defined ARDUINO_T_Watch || defined ARDUINO_T_WATCH // TWatch, all models #define SD_PLATFORM_NAME "TTGO TWatch" #elif defined ARDUINO_M5STACK_ATOM_AND_TFCARD #define SD_PLATFORM_NAME "Atom" @@ -49,3 +51,15 @@ #else #define SD_PLATFORM_NAME "ESP32" #endif + +#if !defined(TFCARD_CS_PIN) // override this from your sketch if the guess is wrong + #if defined ARDUINO_LOLIN_D32_PRO || defined ARDUINO_M5STACK_Core2|| defined ARDUINO_M5STACK_CORE2 || defined ARDUINO_M5Stack_Core_ESP32 || defined ARDUINO_M5STACK_CORE_ESP32 || defined ARDUINO_M5STACK_FIRE || defined ARDUINO_M5STACK_CORES3 + #define TFCARD_CS_PIN 4 + #elif defined( ARDUINO_ESP32_WROVER_KIT ) || defined( ARDUINO_ODROID_ESP32 ) + #define TFCARD_CS_PIN 22 + #elif defined ARDUINO_TWATCH_BASE || defined ARDUINO_TWATCH_2020_V1 || defined ARDUINO_TWATCH_2020_V2 || defined(ARDUINO_TTGO_T1) + #define TFCARD_CS_PIN 13 + #else + #define TFCARD_CS_PIN SS + #endif +#endif diff --git a/src/misc/types.h b/src/misc/types.h index d17bf578..a8463803 100644 --- a/src/misc/types.h +++ b/src/misc/types.h @@ -7,17 +7,14 @@ #define FN_LAMBDA_VOID(x) []() { } #define FN_LAMBDA_BOOL(x) []() -> bool { return x; } -#define FB_LAMBDA_FALSE []() -> bool { return false; } -#pragma GCC diagnostic ignored "-Wunused-function" -#pragma GCC diagnostic ignored "-Wunused-variable" - +#define FN_LAMBDA_FALSE []() -> bool { return false; } namespace SDUpdaterNS { namespace UpdateInterfaceNS { - static bool mode_z = false; + [[maybe_unused]] static bool mode_z = false; typedef std::function THandlerFunction_Progress; struct UpdateManagerInterface_t { @@ -80,9 +77,9 @@ namespace SDUpdaterNS triggerDeinitCb finalize; }; - static int serial( char* labelLoad, char* labelSkip, char* labelSave, unsigned long waitdelay=5000 ); - [[maybe_unused]] static int pushButton( char* labelLoad, char* labelSkip, char* labelSave, unsigned long waitdelay=5000 ); - [[maybe_unused]] static int touchButton( char* labelLoad, char* labelSkip, char* labelSave, unsigned long waitdelay=5000 ); + //[[maybe_unused]] static int serial( char* labelLoad, char* labelSkip, char* labelSave, unsigned long waitdelay=5000 ); + //[[maybe_unused]] static int pushButton( char* labelLoad, char* labelSkip, char* labelSave, unsigned long waitdelay=5000 ); + //[[maybe_unused]] static int touchButton( char* labelLoad, char* labelSkip, char* labelSave, unsigned long waitdelay=5000 ); } @@ -120,6 +117,16 @@ namespace SDUpdaterNS bool changed() { return cb ? cb() : false; } // trigger checker SDUBtnActions val; // button value to return when action is triggered }; + + // abstract filesystem config + struct FS_Config_t + { + const char* name; + void *fsPtr; + void *cfgPtr; + }; + + }; // directly callable (no poll, no pinMode) button @@ -193,7 +200,7 @@ namespace SDUpdaterNS MsgFontColor[0] = _MsgFontColor[0]; MsgFontColor[1] = _MsgFontColor[1]; } - // 16bit colors: Border Fill Text Shadow + // 16bit colors: Border Fill Text Shadow const BtnStyle_t Load{ 0x73AE, 0x630C, 0xFFFF, 0x0000 }; const BtnStyle_t Skip{ 0x73AE, 0x4208, 0xFFFF, 0x0000 }; const BtnStyle_t Save{ 0x73AE, 0x2104, 0xFFFF, 0x0000 }; diff --git a/src/misc/update_interface.hpp b/src/misc/update_interface.hpp deleted file mode 100644 index 138d96c0..00000000 --- a/src/misc/update_interface.hpp +++ /dev/null @@ -1,66 +0,0 @@ -#pragma once - - -#if defined SDU_HAS_TARGZ - - using namespace SDUpdaterNS::UpdateInterfaceNS; - - #define F_Update GzUpdateClass::getInstance() - #define F_UpdateEnd() (mode_z ? F_Update.endgz() : F_Update.end()) - #define F_abort() if (mode_z) F_Update.abortgz(); else F_Update.abort() - #define F_writeStream(updateSource,updateSize) (mode_z ? F_Update.writeGzStream(updateSource,updateSize) : F_Update.writeStream(updateSource)) - #define F_canBegin( usize ) (mode_z ? F_Update.begingz(UPDATE_SIZE_UNKNOWN) : F_Update.begin(usize)) - #define F_end() (mode_z ? F_Update.endgz() : F_Update.end() ) - - namespace SDUpdaterNS - { - namespace ConfigManager - { - static UpdateInterfaceNS::UpdateManagerInterface_t Iface = - { - .begin=[](size_t s)->bool{ return F_canBegin(s); }, - .writeStream=[](Stream &data,size_t size)->size_t{ return F_writeStream(data, size); }, - .abort=[]() { F_abort(); }, - .end=[]()->bool{ return F_end(); }, - .isFinished=[]()->bool{ return F_Update.isFinished(); }, - .canRollBack=[]()->bool{ return F_Update.canRollBack(); }, - .rollBack=[]()->bool{ return F_Update.rollBack(); }, - .onProgress=[](UpdateClass::THandlerFunction_Progress fn){ F_Update.onProgress(fn); }, - .getError=[]()->uint8_t{ return F_Update.getError(); }, - .setBinName=[]( String& fileName, Stream* stream ) { - if( !fileName.endsWith(".gz") ) { - log_d("Not a gz file"); - return; - } - mode_z = stream->peek() == 0x1f; // magic zlib byte - log_d("compression: %s", mode_z ? "enabled" : "disabled" ); - } - }; - }; - }; - -#else - namespace SDUpdaterNS - { - namespace ConfigManager - { - static UpdateInterfaceNS::UpdateManagerInterface_t Iface = - { - .begin=[](size_t s)->bool{ return Update.begin(s); }, - .writeStream=[](Stream &data,size_t size)->size_t{ return Update.writeStream(data); }, - .abort=[]() { Update.abort(); }, - .end=[]()->bool{ return Update.end(); }, - .isFinished=[]()->bool{ return Update.isFinished(); }, - .canRollBack=[]()->bool{ return Update.canRollBack(); }, - .rollBack=[]()->bool{ return Update.rollBack(); }, - .onProgress=[](UpdateClass::THandlerFunction_Progress fn){ Update.onProgress(fn); }, - .getError=[]()->uint8_t{ return Update.getError(); }, - .setBinName=[](String&fileName, Stream* stream){ - if( fileName.endsWith(".gz") ) { - log_e("Gz file detected but gz support is disabled!"); - } - } - }; - }; - } -#endif