diff --git a/src/Afterburner.cpp b/src/Afterburner.cpp index 71842b6..86eb1b3 100644 --- a/src/Afterburner.cpp +++ b/src/Afterburner.cpp @@ -114,6 +114,7 @@ #include #include #include +#include // SSID & password now stored in NV storage - these are still the default values. //#define AP_SSID "Afterburner" @@ -323,6 +324,9 @@ void setup() { digitalWrite(GPIOout1_pin, LOW); digitalWrite(GPIOout2_pin, LOW); + nvs_stats_t nvs_stats; + esp_err_t err = nvs_get_stats(NULL, &nvs_stats); + // initialise TelnetSpy (port 23) as well as Serial to 115200 // Serial is the usual USB connection to a PC // DO THIS BEFORE WE TRY AND SEND DEBUG INFO! @@ -351,6 +355,7 @@ void setup() { DebugPort.printf("Board revision: V%.1f\r\n", float(BoardRevision) * 0.1); DebugPort.printf("ESP32 IDF Version: %s\r\n", esp_get_idf_version()); + DebugPort.printf("NVS: entries- free=%d used=%d total=%d namespace count=%d\r\n", nvs_stats.free_entries, nvs_stats.used_entries, nvs_stats.total_entries, nvs_stats.namespace_count); // Initialize SPIFFS if(!SPIFFS.begin(true)){ @@ -1330,7 +1335,7 @@ bool isCyclicActive() void setupGPIO() { - if(BoardRevision) { + if(BoardRevision == 10 || BoardRevision == 20 || BoardRevision == 21) { // some special considerations for GPIO inputs, depending upon PCB hardware // V1.0 PCBs only expose bare inputs, which are pulled high. Active state into ESP32 is LOW. // V2.0+ PCBs use an input transistor buffer. Active state into ESP32 is HIGH (inverted). @@ -1363,7 +1368,7 @@ void setupGPIO() GPIOalg.begin(GPIOalg_pin, algMode); } else { - // unknown board - deny all GPIO operation (unlikely) + // unknown board or forced no GPIO by grounding pin26 - deny all GPIO operation GPIOin.begin(0, 0, GPIOinNone, LOW); GPIOout.begin(0, 0, GPIOoutNone); GPIOalg.begin(ADC1_CHANNEL_5, GPIOalgNone); @@ -1379,10 +1384,14 @@ bool toggleGPIOout(int channel) return false; } -void setGPIOout(int channel, bool state) +bool setGPIOout(int channel, bool state) { - DebugPort.printf("setGPIO: Output #%d = %d\r\n", channel+1, state); - GPIOout.setState(channel, state); + if(GPIOout.getMode() != GPIOoutNone) { + DebugPort.printf("setGPIO: Output #%d = %d\r\n", channel+1, state); + GPIOout.setState(channel, state); + return true; + } + return false; } bool getGPIOout(int channel) diff --git a/src/OLED/ScreenManager.cpp b/src/OLED/ScreenManager.cpp index 4480317..394cd8d 100644 --- a/src/OLED/ScreenManager.cpp +++ b/src/OLED/ScreenManager.cpp @@ -52,7 +52,29 @@ #include "fonts/MidiFont.h" #include "../Protocol/Protocol.h" #include "fonts/Arial.h" +#include +#pragma pack ( push, 1) +struct sBMPhdr { + char b0; + char b1; + uint32_t filesize; + uint16_t resv1; + uint16_t resv2; + uint32_t startofs; + uint32_t hdrsize; + uint32_t width; + uint32_t height; + uint16_t numcolorplanes; + uint16_t bitsperpixel; + uint32_t compmethod; + uint32_t imagesize; + uint32_t hRes; + uint32_t vRes; + uint32_t numColorsPalette; + uint32_t numImportantColors; +}; +#pragma pack (pop) //////////////////////////////////////////////////////////////////////////////////////////////// // splash creen created using image2cpp http://javl.github.io/image2cpp/ @@ -202,6 +224,114 @@ const uint8_t DieselSplash [] PROGMEM = }; +void storeSplashScreen(const uint8_t* image) +{ + Preferences preferences; + + DebugPort.println("Storing new splash screen"); + preferences.begin("splashscreen", false); + preferences.putBytes("image", image, 1024); + preferences.end(); +} + +void loadSplashScreen(uint8_t* image) +{ + Preferences preferences; + + preferences.begin("splashscreen", false); + int size = preferences.getBytes("image", image, 1024); + preferences.end(); + + if(size == 0) { + storeSplashScreen(DieselSplash); + memcpy(image, DieselSplash, 1024); + } +} + +void storeSplashScreenFile() +{ + if(SPIFFS.exists("/splash.bmp")) { // If a splash.bmp file was uploaded + File file = SPIFFS.open("/splash.bmp", "rb"); // Open it + sBMPhdr header; + file.readBytes((char*)&header, 0x3e); + do { + if(header.b0 != 'B' || header.b1 != 'M') { + DebugPort.println("Bad BMP header"); + break; + } + if(header.width != 128 || header.height != 64) { + DebugPort.println("Bad BMP size"); + break; + } + file.seek(header.startofs); + bool bOK = true; + uint8_t image[1024]; + uint8_t line[128]; + switch(header.bitsperpixel) { + case 1: + DebugPort.println("Reading monochrome bitmap file for splash screen"); + memset(image, 0, 1024); + for(int i=0; i<64; i++) { + file.readBytes((char*)line, 16); + for(int j=0; j < 16; j++) + line[j] ^= 0xff; // invert black/white + memcpy(&image[(63-i)*16], line, 16); + } + break; + case 4: + DebugPort.println("Reading 16 color bitmap file for splash screen"); + memset(image, 0, 1024); + for(int i=0; i<64; i++) { + file.readBytes((char*)line, 64); + for(int j=0; j < 16; j++) { + uint8_t packed = 0; + for(int k=0; k<4; k++) { + packed <<= 2; + uint8_t hold = line[k+j*4]; + if((hold & 0xf0) == 0) + packed |= 0x02; + if((hold & 0x0f) == 0) + packed |= 0x01; + } + line[j] = packed; + } + memcpy(&image[(63-i)*16], line, 16); + } + break; + case 8: + DebugPort.println("Reading 256 color bitmap file for splash screen"); + memset(image, 0, 1024); + for(int i=0; i<64; i++) { + file.readBytes((char*)line, 128); + for(int j=0; j < 16; j++) { + uint8_t packed = 0; + for(int k=0; k<8; k++) { + packed <<= 1; + if(line[k+j*8] == 0) + packed |= 0x01; + } + line[j] = packed; + } + memcpy(&image[(63-i)*16], line, 16); + } + break; + default: + DebugPort.println("Bad BMP bpp"); + bOK = false; + break; + } + + if(bOK) + storeSplashScreen(image); + + } while(0); + + file.close(); + + SPIFFS.remove("/splash.bmp"); + } +} + CScreenManager::CScreenManager() { @@ -249,7 +379,10 @@ CScreenManager::begin(bool bNoClock) // replace adafruit splash screen _pDisplay->clearDisplay(); - _pDisplay->drawBitmap(0, 0, DieselSplash, 128, 64, WHITE); + uint8_t splash[1024]; + loadSplashScreen(splash); + _pDisplay->drawBitmap(0, 0, splash, 128, 64, WHITE); +// _pDisplay->drawBitmap(0, 0, DieselSplash, 128, 64, WHITE); _pDisplay->setCursor(90, 56); CTransientFont AF(*_pDisplay, &segoeUI_Italic_7ptFontInfo); // temporarily use a midi font _pDisplay->setTextColor(WHITE); @@ -269,7 +402,8 @@ CScreenManager::begin(bool bNoClock) if(!bNoClock) menuloop.push_back(new CClockScreen(*_pDisplay, *this)); // clock menuloop.push_back(new CPrimingScreen(*_pDisplay, *this)); // mode / priming - menuloop.push_back(new CGPIOInfoScreen(*_pDisplay, *this)); // GPIO info + if(getBoardRevision() != 0 && getBoardRevision() != 22) + menuloop.push_back(new CGPIOInfoScreen(*_pDisplay, *this)); // GPIO info menuloop.push_back(new CMenuTrunkScreen(*_pDisplay, *this)); _Screens.push_back(menuloop); @@ -304,7 +438,8 @@ CScreenManager::begin(bool bNoClock) menuloop.push_back(new CThermostatModeScreen(*_pDisplay, *this)); // thermostat settings screen menuloop.push_back(new CHomeMenuSelScreen(*_pDisplay, *this)); // Home menu settings screen menuloop.push_back(new COtherOptionsScreen(*_pDisplay, *this)); // Other options screen - menuloop.push_back(new CGPIOScreen(*_pDisplay, *this)); // GPIO settings screen + if(getBoardRevision() != 0 && getBoardRevision() != 22) + menuloop.push_back(new CGPIOScreen(*_pDisplay, *this)); // GPIO settings screen _Screens.push_back(menuloop); // create System Settings screens loop @@ -630,4 +765,5 @@ CScreenManager::_dim(bool state) { _bDimmed = state; _pDisplay->dim(state); -} \ No newline at end of file +} + diff --git a/src/OLED/ScreenManager.h b/src/OLED/ScreenManager.h index 984d209..ddcd112 100644 --- a/src/OLED/ScreenManager.h +++ b/src/OLED/ScreenManager.h @@ -46,7 +46,7 @@ class CScreenManager { void _dim(bool state); public: enum eUIMenuSets { RootMenuLoop, TimerMenuLoop, TuningMenuLoop, UserSettingsLoop, SystemSettingsLoop, BranchMenu }; - enum eUIRootMenus { DetailedControlUI, BasicControlUI, ClockUI, ModeUI, /* CommsUI,*/ GPIOInfoUI, TrunkUI }; + enum eUIRootMenus { DetailedControlUI, BasicControlUI, ClockUI, ModeUI, GPIOInfoUI, TrunkUI }; enum eUITimerMenus { TimerOverviewUI, Timer1UI, Timer2UI, Timer3UI, Timer4UI, Timer5UI, Timer6UI, Timer7UI, Timer8UI, Timer9UI, Timer10UI, Timer11UI, Timer12UI, Timer13UI, Timer14UI }; enum eUITuningMenus { MixtureUI, HeaterSettingsUI, FuelCalUI }; diff --git a/src/Utility/BoardDetect.cpp b/src/Utility/BoardDetect.cpp index 42c751d..01fe8af 100644 --- a/src/Utility/BoardDetect.cpp +++ b/src/Utility/BoardDetect.cpp @@ -50,12 +50,13 @@ // a reliable read. // // Input state truth table -// GPIO26 GPIO33 -// ------ ------ -// V1.0 HIGH HIGH -// unmodified V2.0 HIGH LOW -// modified V2.0 LOW HIGH -// V2.1 LOW HIGH +// GPIO25 GPIO26 GPIO33 +// ------ ------ ------ +// V1.0 HIGH HIGH HIGH +// unmodified V2.0 LOW HIGH LOW +// modified V2.0 LOW LOW HIGH +// V2.1 LOW LOW HIGH +// No GPIO V2.0 HIGH LOW HIGH // // // **************************************************************************************** @@ -94,31 +95,38 @@ int BoardDetect() } DebugPort.println("Board detect: Virgin system - attempting to detect revision"); + pinMode(25, INPUT_PULLUP); pinMode(33, INPUT_PULLUP); pinMode(26, INPUT_PULLUP); // there is a 100nF capacitor across the analogue input, allow that to charge before testing delay(100); + int pin25 = digitalRead(25); int pin33 = digitalRead(33); int pin26 = digitalRead(26); - if(pin33 == HIGH && pin26 == HIGH) { + if((pin33 == HIGH) && (pin26 == HIGH) && (pin25 == HIGH)) { revision = 10; DebugPort.println("Board detect: digital input test reveals V1.x PCB"); } - else if(pin33 == LOW && pin26 == HIGH) { + else if((pin33 == LOW) && (pin26 == HIGH) && (pin25 == LOW)) { revision = 20; DebugPort.println("Board detect: digital input test reveals V2.0 PCB"); } - else if(pin33 == HIGH && pin26 == LOW) { + else if((pin33 == HIGH) && (pin26 == LOW) && (pin25 == LOW)) { revision = 21; DebugPort.println("Board detect: digital input test reveals V2.1 PCB"); } + else if((pin33 == HIGH) && (pin26 == LOW) && (pin25 == HIGH)) { + revision = 22; + DebugPort.println("Board detect: digital input test reveals V2.0 PCB - no GPIO"); + } else { DebugPort.println("Board detect: digital input test failed to detect a valid combination!!!"); } pinMode(33, INPUT); // revert to normal inputs (remove pull ups) pinMode(26, INPUT); + pinMode(25, INPUT); // revert to normal inputs (remove pull ups) //store the detected revision if(revision) { diff --git a/src/Utility/helpers.h b/src/Utility/helpers.h index 11265f7..2380b4a 100644 --- a/src/Utility/helpers.h +++ b/src/Utility/helpers.h @@ -68,7 +68,7 @@ const char* getVersionStr(); extern const char* getVersionDate(); extern int getBoardRevision(); extern void setupGPIO(); -extern void setGPIOout(int channel, bool state); +extern bool setGPIOout(int channel, bool state); extern bool getGPIOout(int channel); extern bool toggleGPIOout(int channel); extern void feedWatchdog(); diff --git a/src/WiFi/BTCWebServer.cpp b/src/WiFi/BTCWebServer.cpp index 42d7a86..e138d57 100644 --- a/src/WiFi/BTCWebServer.cpp +++ b/src/WiFi/BTCWebServer.cpp @@ -49,6 +49,8 @@ extern const char* updateIndex; extern const char* formatDoneContent; extern const char* rebootIndex; +extern void storeSplashScreenFile(); + sBrowserUpload BrowserUpload; WebServer server(80); WebSocketsServer webSocket = WebSocketsServer(81); @@ -693,6 +695,7 @@ void onUploadCompletion() // completion functionality if(BrowserUpload.isSPIFFSupload()) { if(BrowserUpload.isOK()) { + storeSplashScreenFile(); DebugPort.println("WEB: SPIFFS OK"); server.send(200, "text/plain", "OK - File uploaded to SPIFFS"); // javascript reselects the /update page!