From 367266bbc77e8e7671ca3d787a5929c5d7941297 Mon Sep 17 00:00:00 2001 From: tobozo Date: Sat, 11 Dec 2021 19:47:36 +0100 Subject: [PATCH 1/3] Better M5Unified and LFGX support --- .../LGFX-SDLoader-Snippet.ino | 45 ++--- examples/M5Unified/M5Unified.ino | 8 +- src/M5StackUpdater.cpp | 30 +-- src/M5StackUpdater.h | 6 +- src/M5StackUpdaterConfig.h | 43 +++++ src/M5StackUpdaterUI.h | 177 +++++++++--------- src/gitTagVersion.h | 2 +- 7 files changed, 165 insertions(+), 146 deletions(-) diff --git a/examples/LGFX-SDLoader-Snippet/LGFX-SDLoader-Snippet.ino b/examples/LGFX-SDLoader-Snippet/LGFX-SDLoader-Snippet.ino index 806e127d..da909d46 100644 --- a/examples/LGFX-SDLoader-Snippet/LGFX-SDLoader-Snippet.ino +++ b/examples/LGFX-SDLoader-Snippet/LGFX-SDLoader-Snippet.ino @@ -7,7 +7,7 @@ // #define LGFX M5GFX // just alias to LGFX for SD-Updater #include "M5Stack_Buttons.h" // stolen from M5Stack Core -#define TFCARD_CS_PIN 4 +#define TFCARD_CS_PIN 22 #define LGFX_ONLY #define SDU_APP_NAME "LGFX Loader Snippet" @@ -19,6 +19,10 @@ static Button *BtnA; static Button *BtnB; static Button *BtnC; +bool buttonAPressed() { return BtnA->isPressed(); } +bool buttonBPressed() { return BtnB->isPressed(); } +bool buttonCPressed() { return BtnC->isPressed(); } + void ButtonUpdate() { BtnA->read(); @@ -26,29 +30,6 @@ void ButtonUpdate() BtnC->read(); } -static int myActionTrigger( char* labelLoad, char* labelSkip, char* labelSave, unsigned long waitdelay ) -{ - if( waitdelay > 100 ) { // show button labels - //SDUCfg.onBefore(); - SDUCfg.onSplashPage( "SD Updater Options" ); - BtnStyles btns; // use default theme from library - SDUCfg.onButtonDraw( labelLoad, 0, btns.Load.BorderColor, btns.Load.FillColor, btns.Load.TextColor, btns.Load.ShadowColor ); - SDUCfg.onButtonDraw( labelSkip, 1, btns.Skip.BorderColor, btns.Skip.FillColor, btns.Skip.TextColor, btns.Skip.ShadowColor ); - #if defined SDU_APP_PATH - if( SDU_APP_PATH!=nullptr ) { - SDUCfg.onButtonDraw( labelSave, 1, btns.Save.BorderColor, btns.Save.FillColor, btns.Save.TextColor, btns.Save.ShadowColor ); - } - #endif - } - auto msec = millis(); - do { - ButtonUpdate(); - if( BtnA->isPressed() ) return 1; // SD-Load menu (or rollback if avaiblable) - if( BtnB->isPressed() ) return 0; // skip SD Loader screen - if( BtnB->isPressed() ) return 2; // save sketch to FS - } while (millis() - msec < waitdelay); - return -1; -} void setup() { @@ -56,12 +37,17 @@ void setup() tft.init(); - BtnA = new Button(39, true, 10); - BtnB = new Button(38, true, 10); - BtnC = new Button(37, true, 10); + BtnA = new Button(32, true, 10); + BtnB = new Button(33, true, 10); + BtnC = new Button(13, true, 10); ButtonUpdate(); setSDUGfx( &tft ); // attach LGFX to SD-Updater + SDUCfg.setSDUBtnA( &buttonAPressed ); + SDUCfg.setSDUBtnB( &buttonBPressed ); + SDUCfg.setSDUBtnC( &buttonCPressed ); + SDUCfg.setSDUBtnPoller( &ButtonUpdate ); + // SDUCfg.setProgressCb ( myProgress ); // void (*onProgress)( int state, int size ) // SDUCfg.setMessageCb ( myDrawMsg ); // void (*onMessage)( const String& label ) // SDUCfg.setErrorCb ( myErrorMsg ); // void (*onError)( const String& message, unsigned long delay ) @@ -69,13 +55,12 @@ void setup() // SDUCfg.setAfterCb ( myAfterCb ); // void (*onAfter)() // SDUCfg.setSplashPageCb( myDrawSplashPage ); // void (*onSplashPage)( const char* msg ) // SDUCfg.setButtonDrawCb( myDrawPushButton ); // void (*onButtonDraw)( const char* label, uint8_t position, uint16_t outlinecolor, uint16_t fillcolor, uint16_t textcolor ) - SDUCfg.setWaitForActionCb( myActionTrigger ); // int (*onWaitForAction)( char* labelLoad, char* labelSkip, unsigned long waitdelay ) - + // SDUCfg.setWaitForActionCb( myActionTrigger ); // int (*onWaitForAction)( char* labelLoad, char* labelSkip, unsigned long waitdelay ) checkSDUpdater( SD, // filesystem (default=SD) MENU_BIN, // path to binary (default=/menu.bin, empty string=rollback only) - 2000, // wait delay, (default=0, will be forced to 2000 upon ESP.restart() ) + 10000, // wait delay, (default=0, will be forced to 2000 upon ESP.restart() ) TFCARD_CS_PIN // (usually default=4 but your mileage may vary) ); diff --git a/examples/M5Unified/M5Unified.ino b/examples/M5Unified/M5Unified.ino index 4671e9a2..6d8a2860 100644 --- a/examples/M5Unified/M5Unified.ino +++ b/examples/M5Unified/M5Unified.ino @@ -1,3 +1,4 @@ +#include #include //#define TFCARD_CS_PIN 4 #include @@ -7,7 +8,7 @@ void setup(void) M5.begin(); Serial.begin(115200); - SDUCfg.setLabelMenu("< Menu"); // BtnA label: load menu.bin + SDUCfg.setLabelMenu("< Menu"); // BtnA label: load menu.bin SDUCfg.setLabelSkip("Launch"); // BtnB label: skip the lobby countdown and run the app SDUCfg.setLabelSave("Save"); // BtnC label: save the sketch to the SD SDUCfg.setAppName("M5Unified test"); // lobby screen label: application name @@ -16,13 +17,16 @@ void setup(void) checkSDUpdater( SD, // filesystem (default=SD) MENU_BIN, // path to binary (default=/menu.bin, empty string=rollback only) - 150000, // wait delay, (default=0, will be forced to 2000 upon ESP.restart() ) + 15000, // wait delay, (default=0, will be forced to 2000 upon ESP.restart() ) TFCARD_CS_PIN // usually default=4 but your mileage may vary ); + + M5.Display.print("M5Unified test"); } void loop(void) { // do your stuff + } diff --git a/src/M5StackUpdater.cpp b/src/M5StackUpdater.cpp index dd9399f2..719380e0 100644 --- a/src/M5StackUpdater.cpp +++ b/src/M5StackUpdater.cpp @@ -59,7 +59,6 @@ void SDUpdater::_error( const char **errMsgs, uint8_t msgCount, unsigned long wa for( int i=0; i buf(new uint8_t[bufSize]); @@ -221,7 +219,6 @@ bool SDUpdater::saveSketchToFS( fs::FS &fs, const char* binfilename, bool skipIf } - // rollback helper, save menu.bin meta info in NVS void SDUpdater::updateNVS() { @@ -240,6 +237,7 @@ void SDUpdater::updateNVS() preferences.end(); } + // perform the actual update from a given stream void SDUpdater::performUpdate( Stream &updateSource, size_t updateSize, String fileName ) { @@ -272,6 +270,7 @@ void SDUpdater::performUpdate( Stream &updateSource, size_t updateSize, String f } } + // forced rollback (doesn't check NVS digest) void SDUpdater::doRollBack( const String& message ) { @@ -300,7 +299,6 @@ void SDUpdater::doRollBack( const String& message ) } - // if NVS has info about MENU_BIN flash size and digest, try rollback() void SDUpdater::tryRollback( String fileName ) { @@ -345,7 +343,6 @@ void SDUpdater::tryRollback( String fileName ) } - // do perform update void SDUpdater::updateFromStream( Stream &stream, size_t updateSize, const String& fileName ) { @@ -360,19 +357,20 @@ void SDUpdater::updateFromStream( Stream &stream, size_t updateSize, const Strin } - void SDUpdater::updateFromFS( fs::FS &fs, const String& fileName ) { cfg->setFS( &fs ); updateFromFS( fileName ); } + void SDUpdater::checkSDUpdaterHeadless( fs::FS &fs, String fileName, unsigned long waitdelay ) { cfg->setFS( &fs ); checkSDUpdaterHeadless( fileName, waitdelay ); } + void SDUpdater::checkSDUpdaterUI( fs::FS &fs, String fileName, unsigned long waitdelay ) { cfg->setFS( &fs ); @@ -380,7 +378,6 @@ void SDUpdater::checkSDUpdaterUI( fs::FS &fs, String fileName, unsigned long wai } - void SDUpdater::updateFromFS( const String& fileName ) { if( cfg->fs == nullptr ) { @@ -404,7 +401,6 @@ void SDUpdater::updateFromFS( const String& fileName ) log_d("Skipping rollback per config"); } } - // no rollback possible, start filesystem if( !_fsBegin() ) { const char* msg[] = {"No filesystem mounted.", "Can't load firmware."}; @@ -423,8 +419,6 @@ void SDUpdater::updateFromFS( const String& fileName ) size_t updateSize = updateBin.size(); - //log_d("File %s exists (%d bytes)", fileName.c_str(), updateSize ); - updateFromStream( updateBin, updateSize, fileName ); updateBin.close(); @@ -446,14 +440,14 @@ void SDUpdater::checkSDUpdaterHeadless( String fileName, unsigned long waitdelay if( cfg->onWaitForAction ) { int ret = cfg->onWaitForAction( nullptr, nullptr, nullptr, waitdelay ); - if ( ret == 1 ) { + if ( ret == SDU_BTNA_MENU ) { Serial.printf( SDU_LOAD_TPL, fileName.c_str() ); updateFromFS( fileName ); ESP.restart(); } if( cfg->binFileName != nullptr ) { log_d("Checking if %s needs saving", cfg->binFileName ); - saveSketchToFS( *cfg->fs, cfg->binFileName, ret != 2 ); + saveSketchToFS( *cfg->fs, cfg->binFileName, ret != SDU_BTNC_SAVE ); } } else { _error( "Missing onWaitForAction!" ); @@ -494,7 +488,7 @@ void SDUpdater::checkSDUpdaterUI( String fileName, unsigned long waitdelay ) if( cfg->onWaitForAction ) { int ret = cfg->onWaitForAction( isRollBack ? (char*)cfg->labelRollback : (char*)cfg->labelMenu, (char*)cfg->labelSkip, (char*)cfg->labelSave, waitdelay ); - if ( ret == 1 ) { + if ( ret == SDU_BTNA_MENU ) { if( isRollBack == false ) { Serial.printf( SDU_LOAD_TPL, fileName.c_str() ); updateFromFS( fileName ); @@ -506,7 +500,7 @@ void SDUpdater::checkSDUpdaterUI( String fileName, unsigned long waitdelay ) } if( cfg->binFileName != nullptr ) { log_d("Checking if %s needs saving", cfg->binFileName ); - saveSketchToFS( *cfg->fs, cfg->binFileName, ret != 2 ); + saveSketchToFS( *cfg->fs, cfg->binFileName, ret != SDU_BTNC_SAVE ); } } else { _error( "Missing onWaitForAction!" ); @@ -517,11 +511,3 @@ void SDUpdater::checkSDUpdaterUI( String fileName, unsigned long waitdelay ) if( cfg->onAfter ) cfg->onAfter(); } } - - - - - - - - diff --git a/src/M5StackUpdater.h b/src/M5StackUpdater.h index 58154129..e1293683 100644 --- a/src/M5StackUpdater.h +++ b/src/M5StackUpdater.h @@ -42,6 +42,8 @@ * // #include * // #include * // #include + * // #include + * // #include * * And add this: * @@ -118,7 +120,7 @@ class SDUpdater SDUpdater( config_sdu_t* _cfg ) : cfg(_cfg) { if( SDUCfgLoader ) SDUCfgLoader(); else SetupSDMenuConfig(); - if( cfg->fs == nullptr ) log_w("No filesystem selected!"); + //if( cfg->fs == nullptr ) log_w("No filesystem selected in constructor!"); }; // legacy constructor SDUpdater( const int TFCardCsPin_ = TFCARD_CS_PIN ) { @@ -128,7 +130,7 @@ class SDUpdater cfg = &SDUCfg; if( SDUCfgLoader ) SDUCfgLoader(); else SetupSDMenuConfig(); - if( cfg->fs == nullptr ) log_w("No filesystem selected!"); + //if( cfg->fs == nullptr ) log_w("No filesystem selected in constructor!"); }; // check methods void checkSDUpdaterHeadless( String fileName, unsigned long waitdelay ); diff --git a/src/M5StackUpdaterConfig.h b/src/M5StackUpdaterConfig.h index 9463c9a1..1cd4183b 100644 --- a/src/M5StackUpdaterConfig.h +++ b/src/M5StackUpdaterConfig.h @@ -47,6 +47,16 @@ #define SDU_APP_AUTHOR nullptr #endif +// to be returned by onWaitForActionCb +enum SDUBtnActions +{ + SDU_BTNA_ROLLBACK = 0, + SDU_BTNA_MENU = 1, + SDU_BTNB_SKIP = -1, + SDU_BTNC_SAVE = 2 +}; + + // callback signatures typedef void (*onProgressCb)( int state, int size ); typedef void (*onMessageCb)( const String& label ); @@ -57,6 +67,15 @@ typedef void (*onSplashPageCb)( const char* msg ); typedef void (*onButtonDrawCb)( const char* label, uint8_t position, uint16_t outlinecolor, uint16_t fillcolor, uint16_t textcolor, uint16_t shadowcolor ); typedef int (*onWaitForActionCb)( char* labelLoad, char* labelSkip, char* labelSave, unsigned long waitdelay ); typedef void (*onConfigLoad)(); +typedef void (*BtnPollCb)(); // called to poll button state e.g. like M5.update() +typedef bool (*BtnXPressCb)(); // called when a button is pressed + +// button to action assignment +struct BtnXAction +{ + BtnXPressCb cb; + SDUBtnActions val; +}; // SDUpdater config callbacks and params struct config_sdu_t @@ -73,6 +92,13 @@ struct config_sdu_t const char* appName = SDU_APP_NAME; const char* authorName = SDU_APP_AUTHOR; + BtnXAction Buttons[3] = + { + { nullptr, SDU_BTNA_MENU }, + { nullptr, SDU_BTNB_SKIP }, + { nullptr, SDU_BTNC_SAVE } + }; + BtnPollCb buttonsUpdate = nullptr; onProgressCb onProgress = nullptr; onMessageCb onMessage = nullptr; onErrorCb onError = nullptr; @@ -92,6 +118,7 @@ struct config_sdu_t void setSplashPageCb( onSplashPageCb cb ) { onSplashPage = cb; } void setButtonDrawCb( onButtonDrawCb cb ) { onButtonDraw = cb; } void setWaitForActionCb( onWaitForActionCb cb ) { onWaitForAction = cb; } + void setSDUBtnPoller( BtnPollCb cb ) { buttonsUpdate = cb; } void setLabelMenu( const char* label ) { labelMenu = label; } void setLabelSkip( const char* label ) { labelSkip = label; } @@ -102,6 +129,22 @@ struct config_sdu_t void setBinFileName( const char* name ) { binFileName = name; } void useRolllback( bool use ) { use_rollback = use; } + void setSDUBtnA( BtnXPressCb Btn ) { setSDUBtns(SDU_BTNA_MENU, Btn ); } + void setSDUBtnB( BtnXPressCb Btn ) { setSDUBtns(SDU_BTNB_SKIP, Btn ); } + void setSDUBtnC( BtnXPressCb Btn ) { setSDUBtns(SDU_BTNC_SAVE, Btn ); } + void setSDUBtns( SDUBtnActions BtnVal, BtnXPressCb cb ) + { + int _id = -1; + switch( BtnVal ) { + case SDU_BTNA_MENU: _id = 0; break; + case SDU_BTNB_SKIP: _id = 1; break; + case SDU_BTNC_SAVE: _id = 2; break; + default: log_e("Invalid button val: %d", BtnVal ); return; break; + } + Buttons[_id].cb = cb; + Buttons[_id].val = BtnVal; + } + }; // override this from sketch diff --git a/src/M5StackUpdaterUI.h b/src/M5StackUpdaterUI.h index 78f137e2..e4d3b9e8 100644 --- a/src/M5StackUpdaterUI.h +++ b/src/M5StackUpdaterUI.h @@ -90,6 +90,13 @@ static void SDMenuProgressHeadless( int state, int size ) { SDuGFX = gfx; } + namespace SDU + { + static void pollButtons() { } + static bool buttonAPressed() { return false; }; + static bool buttonBPressed() { return false; }; + static bool buttonCPressed() { return false; }; + }; #define HAS_LGFX // LFGX family cores/drivers (ESP32-Chimera-Core, LovyanGFX, M5GFX, M5Unified) #define SDUSprite LGFX_Sprite #endif @@ -101,6 +108,7 @@ static void SDMenuProgressHeadless( int state, int size ) #define SDU_GFX M5.Display // M5Unified has a different namespace but LGFX compatible API #define HAS_LGFX // LFGX family cores/drivers (ESP32-Chimera-Core, LovyanGFX, M5GFX, M5Unified) #define SDUSprite LGFX_Sprite + //#define SDUButton m5::Button_Class #else #define SDU_GFX M5.Lcd // can be either M5.Lcd from M5Core.h, M5Core2.h, M5StickC.h or ESP32-Chimera-Core.h #if defined _CHIMERA_CORE_H_ @@ -109,7 +117,22 @@ static void SDMenuProgressHeadless( int state, int size ) #else #define SDUSprite TFT_eSprite #endif + //#define SDUButton Button #endif + namespace SDU + { + static void pollButtons() { M5.update(); } + static bool buttonAPressed() { return M5.BtnA.isPressed() ? true:false; } + static bool buttonBPressed() { return M5.BtnB.isPressed() ? true:false; } + static bool buttonCPressed() + { + #if defined _M5STICKC_H_ + return false; + #else + return M5.BtnC.isPressed() ? true:false; + #endif + } + }; #endif #endif @@ -272,7 +295,7 @@ static void SDMenuProgressHeadless( int state, int size ) SDU_GFX.setTextSize( style->fontSize ); SDU_GFX.setTextDatum( style->textDatum ); uint8_t lineHeight = SDU_GFX.fontHeight()*1.8; - #if defined HAS_LGFX + #if defined HAS_LGFX // draw gradient background if( style->colorStart == style->colorEnd ) { SDU_GFX.fillRect( 0, y, SDU_GFX.width(), lineHeight, style->bgColor ); } else { @@ -280,7 +303,7 @@ static void SDMenuProgressHeadless( int state, int size ) SDU_GFX.drawGradientHLine( 0, i, SDU_GFX.width(), style->colorStart, style->colorEnd ); } } - #else + #else // just fill the background SDU_GFX.fillRect( 0, y, SDU_GFX.width(), lineHeight, style->bgColor ); #endif drawTextShadow( msg, x, y+lineHeight/2, style->textColor, TFT_DARKGREY ); @@ -328,88 +351,67 @@ static void SDMenuProgressHeadless( int state, int size ) } - #if defined LGFX_ONLY // has no push button logic - __attribute__((unused)) - static int assertStartUpdateFromPushButton( char* labelLoad, char* labelSkip, char* labelSave, unsigned long waitdelay ) - { - // Dummy function, use SDUCfg.onWaitForAction( fn ) to override - return -1; - } - #else // M5.BtnA/BtnB/BtnC support - __attribute__((unused)) - static int assertStartUpdateFromPushButton( char* labelLoad, char* labelSkip, char* labelSave, unsigned long waitdelay ) - { - if( waitdelay > 100 ) { - SDUCfg.onBefore(); - SDUCfg.onSplashPage( BTN_HINT_MSG ); - BtnStyles btns; - SDUCfg.onButtonDraw( labelLoad, 0, btns.Load.BorderColor, btns.Load.FillColor, btns.Load.TextColor, btns.Load.ShadowColor ); - SDUCfg.onButtonDraw( labelSkip, 1, btns.Skip.BorderColor, btns.Skip.FillColor, btns.Skip.TextColor, btns.Skip.ShadowColor ); - if( SDUCfg.binFileName != nullptr ) { - SDUCfg.onButtonDraw( labelSave, 2, btns.Save.BorderColor, btns.Save.FillColor, btns.Save.TextColor, btns.Save.ShadowColor ); - } - } - auto msec = millis(); - auto lastdraw = millis(); - uint32_t progress = 0, progressOld = 1; - if( SDUCfg.onProgress ) SDUCfg.onProgress( 100, 100 ); - - #if defined HAS_LGFX - SDUSprite *sprite = new SDUSprite( &SDU_GFX ); - sprite->createSprite( 32, 32 ); - #endif - int ret = -1; + __attribute__((unused)) + static int assertStartUpdateFromPushButton( char* labelLoad, char* labelSkip, char* labelSave, unsigned long waitdelay ) + { + if( waitdelay > 100 ) { + SDUCfg.onBefore(); + SDUCfg.onSplashPage( BTN_HINT_MSG ); + BtnStyles btns; + SDUCfg.onButtonDraw( labelLoad, 0, btns.Load.BorderColor, btns.Load.FillColor, btns.Load.TextColor, btns.Load.ShadowColor ); + SDUCfg.onButtonDraw( labelSkip, 1, btns.Skip.BorderColor, btns.Skip.FillColor, btns.Skip.TextColor, btns.Skip.ShadowColor ); + if( SDUCfg.binFileName != nullptr ) { + SDUCfg.onButtonDraw( labelSave, 2, btns.Save.BorderColor, btns.Save.FillColor, btns.Save.TextColor, btns.Save.ShadowColor ); + } + } + auto msec = millis(); + uint32_t progress = 0, progressOld = 1; + if( SDUCfg.onProgress ) SDUCfg.onProgress( 100, 100 ); - Button *ButtonA = &M5.BtnA; // Load Launcher - Button *ButtonB = &M5.BtnB; // Skip Lobby - #if defined _M5STICKC_H_ - Button *ButtonC = nullptr; - #else - Button *ButtonC = SDUCfg.binFileName != nullptr ? &M5.BtnC : nullptr; // Save Sketch to SD - #endif + #if defined HAS_LGFX + SDUSprite *sprite = new SDUSprite( &SDU_GFX ); + sprite->createSprite( 32, 32 ); + #endif - // order matters !! - Button *buttons[3] = { ButtonB, ButtonA, ButtonC }; + int ret = -1; - do { - M5.update(); - for( int i=0; i<3; i++ ) { - if( buttons[i] && buttons[i]->isPressed() ) { ret = i; goto _endAssert; } - } - if( SDUCfg.onProgress ) { - float barprogress = float(millis() - msec) / float(waitdelay); - progress = 100- (100 * barprogress); - if (progressOld != progress) { - progressOld = progress; - SDUCfg.onProgress( (uint8_t)progress, 100 ); - } + do { + if( SDUCfg.buttonsUpdate ) SDUCfg.buttonsUpdate(); + for( int i=0; i<3; i++ ) { + if( SDUCfg.Buttons[i].cb && SDUCfg.Buttons[i].cb() ) { ret = SDUCfg.Buttons[i].val; goto _endAssert; } + } + if( SDUCfg.onProgress ) { + float barprogress = float(millis() - msec) / float(waitdelay); + progress = 100- (100 * barprogress); + if (progressOld != progress) { + progressOld = progress; + SDUCfg.onProgress( (uint8_t)progress, 100 ); } - #if defined HAS_LGFX // this effect needs pushImageRotateZoom support - float angle = sin( float(millis())/500.0 )*180.0; // 1/2 round per second - sprite->clear(); - sprite->pushImageRotateZoom(sprite->width()/2, sprite->height()/2, 7.5, 8, angle, 1, 1, 15, 16, sdUpdaterIcon15x16_raw); - sprite->pushSprite( SDU_GFX.width()/2-sprite->width()/2, SDU_GFX.height()*.75-sprite->height() ); - lastdraw = millis(); - #endif - } while (millis() - msec < waitdelay); + } + #if defined HAS_LGFX // this effect needs pushImageRotateZoom support + float angle = sin( float(millis())/500.0 )*180.0; // 1/2 round per second + sprite->clear(); + sprite->pushImageRotateZoom(sprite->width()/2, sprite->height()/2, 7.5, 8, angle, 1, 1, 15, 16, sdUpdaterIcon15x16_raw); + sprite->pushSprite( SDU_GFX.width()/2-sprite->width()/2, SDU_GFX.height()*.75-sprite->height() ); + #endif + } while (millis() - msec < waitdelay); - _endAssert: + _endAssert: - if( SDUCfg.onProgress ) SDUCfg.onProgress( 0, 100 ); - #if defined HAS_LGFX - sprite->deleteSprite(); - #endif - if( ret > -1 ) { // wait for button release - while( buttons[ret]->isPressed() ) { - M5.update(); - vTaskDelay(10); - } + if( SDUCfg.onProgress ) SDUCfg.onProgress( 0, 100 ); + #if defined HAS_LGFX + sprite->deleteSprite(); + #endif + if( ret > -1 ) { // wait for button release + log_v("Waiting for Button #%d to be released", ret ); + while( SDUCfg.Buttons[ret].cb && SDUCfg.Buttons[ret].cb() ) { + if( SDUCfg.buttonsUpdate ) SDUCfg.buttonsUpdate(); + vTaskDelay(10); } - return ret; } - #endif - + return ret; + } #if defined _M5Core2_H_ // M5Core2.h additional touch support, will soon be deprecated @@ -460,8 +462,6 @@ static void SDMenuProgressHeadless( int state, int size ) static void DisplayUpdateUI( const String& label ) { - //log_d("Entering DisplayUpdateUI"); - if (SDU_GFX.width() < SDU_GFX.height()) SDU_GFX.setRotation(SDU_GFX.getRotation() ^ 1); SDU_GFX.fillScreen( TFT_BLACK ); @@ -480,8 +480,6 @@ static void SDMenuProgressHeadless( int state, int size ) xpos = 0 ; } } - //int progress_w = 102; - //int progress_h = 20; int posX = (SDU_GFX.width() - ProgressStyle.width+2) >> 1; int posY = (SDU_GFX.height()- ProgressStyle.height+2) >> 1; SDU_GFX.setCursor( xpos, posY - 20 ); @@ -503,8 +501,6 @@ static void SDMenuProgressHeadless( int state, int size ) SDU_GFX.setTextDatum( MC_DATUM ); SDU_GFX.drawString( msg.c_str(), SDU_GFX.width()/2, msgposy+headerHeight*2 ); msgposy += headerHeight; - //SDU_GFX.setCursor( SDU_GFX.width()/2, headerHeight*2 ); - //SDU_GFX.print( msg ); delay(wait); } @@ -513,14 +509,17 @@ static void SDMenuProgressHeadless( int state, int size ) { if( SDUCfg.load_defaults ) { - if( !SDUCfg.onProgress ) { SDUCfg.setProgressCb( SDMenuProgressUI ); log_v("Attached onProgress"); } - if( !SDUCfg.onMessage ) { SDUCfg.setMessageCb( DisplayUpdateUI ); log_v("Attached onMessage"); } - if( !SDUCfg.onError ) { SDUCfg.setErrorCb( DisplayErrorUI ); log_v("Attached onError"); } - if( !SDUCfg.onBefore ) { SDUCfg.setBeforeCb( freezeTextStyle ); log_v("Attached onBefore"); } - if( !SDUCfg.onAfter ) { SDUCfg.setAfterCb( thawTextStyle ); log_v("Attached onAfter"); } - if( !SDUCfg.onSplashPage ) { SDUCfg.setSplashPageCb( drawSDUSplashPage ); log_v("Attached onSplashPage"); } - if( !SDUCfg.onButtonDraw ) { SDUCfg.setButtonDrawCb( drawSDUPushButton ); log_v("Attached onButtonDraw"); } - + if( !SDUCfg.Buttons[0].cb ) { SDUCfg.setSDUBtnA( SDU::buttonAPressed ); log_v("Attached buttonpressA"); } + if( !SDUCfg.Buttons[1].cb ) { SDUCfg.setSDUBtnB( SDU::buttonBPressed ); log_v("Attached buttonpressB"); } + if( !SDUCfg.Buttons[2].cb ) { SDUCfg.setSDUBtnC( SDU::buttonCPressed ); log_v("Attached buttonpressC"); } + if( !SDUCfg.buttonsUpdate ) { SDUCfg.setSDUBtnPoller( SDU::pollButtons ); log_v("Attached buttons poller"); } + if( !SDUCfg.onProgress ) { SDUCfg.setProgressCb( SDMenuProgressUI ); log_v("Attached onProgress"); } + if( !SDUCfg.onMessage ) { SDUCfg.setMessageCb( DisplayUpdateUI ); log_v("Attached onMessage"); } + if( !SDUCfg.onError ) { SDUCfg.setErrorCb( DisplayErrorUI ); log_v("Attached onError"); } + if( !SDUCfg.onBefore ) { SDUCfg.setBeforeCb( freezeTextStyle ); log_v("Attached onBefore"); } + if( !SDUCfg.onAfter ) { SDUCfg.setAfterCb( thawTextStyle ); log_v("Attached onAfter"); } + if( !SDUCfg.onSplashPage ) { SDUCfg.setSplashPageCb( drawSDUSplashPage ); log_v("Attached onSplashPage"); } + if( !SDUCfg.onButtonDraw ) { SDUCfg.setButtonDrawCb( drawSDUPushButton ); log_v("Attached onButtonDraw"); } #if defined SDU_HAS_TOUCH // default touch button support if ( !SDUCfg.onWaitForAction) { SDUCfg.setWaitForActionCb( assertStartUpdateFromTouchButton ); log_v("Attached onWaitForAction (touch)"); } #else // default momentary button support diff --git a/src/gitTagVersion.h b/src/gitTagVersion.h index 0e8057fa..4a8630f7 100644 --- a/src/gitTagVersion.h +++ b/src/gitTagVersion.h @@ -1,6 +1,6 @@ #define SDU_VERSION_MAJOR 1 #define SDU_VERSION_MINOR 1 -#define SDU_VERSION_PATCH 7 +#define SDU_VERSION_PATCH 8 #define _SDU_STR(x) #x #define SDU_STR(x) _SDU_STR(x) // Macro to convert library version number into an integer From bf8f806a89b84c4573a0d4d07217ff147992cd90 Mon Sep 17 00:00:00 2001 From: tobozo Date: Sat, 11 Dec 2021 19:48:01 +0100 Subject: [PATCH 2/3] raising version --- .github/workflows/LibraryBuild.yml | 6 ++++++ library.json | 2 +- library.properties | 2 +- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/.github/workflows/LibraryBuild.yml b/.github/workflows/LibraryBuild.yml index 49f4a829..3745c46d 100644 --- a/.github/workflows/LibraryBuild.yml +++ b/.github/workflows/LibraryBuild.yml @@ -28,6 +28,7 @@ jobs: - M5Core2-SD-Menu - M5Fire-SD-Menu - OdroidGo-SD-Menu + #- TTGO-LoRa32-V2-SDLoader-Snippet include: - matrix-context: M5Core2-SDLoader-Snippet @@ -66,6 +67,11 @@ jobs: sketch-names: M5Stack-SD-Menu.ino bin-name: OdroidGo-Launcher.bin required-libraries: "ESP32-Chimera-Core,LovyanGFX,ArduinoJson" + #- matrix-context: TTGO-LoRa32-V2-SDLoader-Snippet + #arduino-boards-fqbn: esp32:esp32:ttgo-lora32-v2 + #sketch-names: TTGO-SDLoader-Snippet.ino + #required-libraries: "ESP32-Chimera-Core,LovyanGFX,ArduinoJson" + fail-fast: false diff --git a/library.json b/library.json index 08506ae9..85af9bf5 100644 --- a/library.json +++ b/library.json @@ -10,7 +10,7 @@ "type": "git", "url": "https://github.com/tobozo/M5Stack-SD-Updater.git" }, - "version": "1.1.7", + "version": "1.1.8", "framework": "arduino", "headers": "M5StackUpdater.h", "platforms": "espressif32" diff --git a/library.properties b/library.properties index 9ea114f9..ef20a27a 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=M5Stack-SD-Updater -version=1.1.7 +version=1.1.8 author=tobozo maintainer=tobozo@noreply.github.com sentence=SD Card Loader for M5 Stack From 59c9e5d3c53ef706bf3cfadb38d465ff93eccccf Mon Sep 17 00:00:00 2001 From: tobozo Date: Sat, 11 Dec 2021 20:18:50 +0100 Subject: [PATCH 3/3] updated documentation --- README.md | 77 ++++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 70 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 0df7405f..69430c44 100644 --- a/README.md +++ b/README.md @@ -95,6 +95,7 @@ The snippet of code in the `M5Stack-SDLoader-Snippet.ino` sketch can be used as // #include // #include // #include + // #include ``` @@ -168,7 +169,21 @@ The snippet of code in the `M5Stack-SDLoader-Snippet.ino` sketch can be used as SDUCfg.setCSPin( TFCARD_CS_PIN ); SDUCfg.setFS( &SD ); - SDUCfg.setWaitForActionCb( mySerialActionTrigger ); // set your own serial input trigger + + // set your own button response trigger + + static int buttonState; + + SDUCfg.setSDUBtnA( []() { + return buttonState==LOW ? true : false; + }); + + SDUCfg.setSDUBtnPoller( []() { + buttonState = digitalRead( 16 ); + }); + + // Or set your own serial input trigger + // SDUCfg.setWaitForActionCb( mySerialActionTrigger ); SDUpdater sdUpdater( &SDUCfg ); @@ -206,6 +221,7 @@ The snippet of code in the `M5Stack-SDLoader-Snippet.ino` sketch can be used as As a result, any atypical setup (e.g. headless+LittleFS) should make use of those callback setters: ```C++ + SDUCfg.setCSPin ( TFCARD_CS_PIN ); // const int SDUCfg.setFS ( &FS ); // fs::FS* (SD, SD_MMC, SPIFFS, LittleFS, PSRamFS) SDUCfg.setProgressCb ( myProgress ); // void (*myProgress)( int state, int size ) SDUCfg.setMessageCb ( myDrawMsg ); // void (*myDrawMsg)( const String& label ) @@ -215,8 +231,12 @@ The snippet of code in the `M5Stack-SDLoader-Snippet.ino` sketch can be used as SDUCfg.setSplashPageCb( myDrawSplashPage ); // void (*myDrawSplashPage)( const char* msg ) SDUCfg.setButtonDrawCb( myDrawPushButton ); // void (*myDrawPushButton)( const char* label, uint8_t position, uint16_t outlinecolor, uint16_t fillcolor, uint16_t textcolor ) SDUCfg.setWaitForActionCb( myActionTrigger ); // int (*myActionTrigger)( char* labelLoad, char* labelSkip, unsigned long waitdelay ) -``` + SDUCfg.setSDUBtnPoller( myButtonPoller ); // void (*myButtonPoller)() + SDUCfg.setSDUBtnA( myBtnAPushedcb ); // bool (*myBtnAPushedcb )() + SDUCfg.setSDUBtnB( myBtnBPushedcb ); // bool (*myBtnBPushedcb )() + SDUCfg.setSDUBtnC( myBtnCPushedcb ); // bool (*myBtnCPushedcb )() +``` @@ -225,6 +245,33 @@ Set custom action trigger for `update`, `rollback`, `save` and `skip` lobby opti // int myActionTrigger( char* labelLoad, char* labelSkip, unsigned long waitdelay ) // return values: 1=update, 0=rollback, -1=skip SDUCfg.setWaitForActionCb( myActionTrigger ); + + // Or separately if a UI is available: + + static int buttonAState; + static int buttonBState; + static int buttonCState; + + SDUCfg.setSDUBtnPoller( []() { + buttonAState = digitalRead( 32 ); + buttonBState = digitalRead( 33 ); + buttonCState = digitalRead( 13 ); + delay(50); + }); + + SDUCfg.setSDUBtnA( []() { + return buttonState==LOW ? true : false; + }); + + SDUCfg.setSDUBtnB( []() { + return buttonState==LOW ? true : false; + }); + + SDUCfg.setSDUBtnC( []() { + return buttonState==LOW ? true : false; + }); + + ``` Example: @@ -237,10 +284,10 @@ static int myActionTrigger( char* labelLoad, char* labelSkip, char* labelSave, do { if( Serial.available() ) { String out = Serial.readStringUntil('\n'); - if( out == "update" ) return 1; // load "/menu.bin" - else if( out == "rollback") return 0; // rollback to other OTA partition - else if( out == "save") return 2; // save current sketch to SD card - else if( out == "skip" ) return -1; // do nothing + if( out == "update" ) return SDU_BTNA_MENU; // load "/menu.bin" + else if( out == "rollback") return SDU_BTNA_ROLLBACK; // rollback to other OTA partition + else if( out == "save") return SDU_BTNC_SAVE; // save current sketch to SD card + else if( out == "skip" ) return SDU_BTNB_SKIP; // do nothing else Serial.printf("Ignored command: %s\n", out.c_str() ); } } while( msec > int64_t( millis() ) - int64_t( waitdelay ) ); @@ -252,6 +299,7 @@ void setup() Serial.begin(115200); SDUCfg.setAppName( "My Application" ); // lobby screen label: application name + SDUCfg.setAuthorName( "by @myself" ); // lobby screen label: application author SDUCfg.setBinFileName( "/MyApplication.bin" ); // if file path to bin is set for this app, it will be checked at boot and created if not exist SDUCfg.setWaitForActionCb( myActionTrigger ); @@ -304,6 +352,21 @@ Set buttons drawing function (useful with Touch displays) SDUCfg.setButtonDrawCb( myDrawPushButton ); ``` +Set buttons state polling function (typically M5.update() +```C++ + // void(*myButtonPollCb)(); + SDUCfg.setSDUBtnPoller( myButtonPollCb ); +``` + +Set each button state getter function, it must return true when the state is "pushed". +```C++ + SDUCfg.setSDUBtnA( myBtnAPushedcb ); // bool (*myBtnAPushedcb )() + SDUCfg.setSDUBtnB( myBtnBPushedcb ); // bool (*myBtnBPushedcb )() + SDUCfg.setSDUBtnC( myBtnCPushedcb ); // bool (*myBtnCPushedcb )() +``` + + +

@@ -357,7 +420,7 @@ The default SD-Menu application will scan for these file types: 🔘 OPTIONAL: ------------ -- The lobby screen at boot can be customized using `SDUCfg.setAppName` and `SDUCfg.setBinFileName`. +- The lobby screen at boot can be customized using `SDUCfg.setAppName`, `SDUCfg.setAuthorName` and `SDUCfg.setBinFileName`. When set, the app name and the binary path will be visible on the lobby screen, and an extra button `Button C` labelled `Save` is added to the UI. Pushing this button while the M5Stack is booting will create or overwrite the sketch binary to the SD Card. This can be triggered manually by using `saveSketchToFS(SD, fileName, TFCARD_CS_PIN)`.