Added ability to upload custom splash ScreenFlowV3.dia.

Added 4th board type - GPIO disabled on V2.0 PCB - install 0R in C6, leave other bits out.
This commit is contained in:
Ray Jones 2019-08-01 22:57:18 +10:00
parent 945d9c88b7
commit ac091fa6d8
6 changed files with 176 additions and 20 deletions

View file

@ -114,6 +114,7 @@
#include <rom/rtc.h> #include <rom/rtc.h>
#include <esp_spiffs.h> #include <esp_spiffs.h>
#include <SPIFFS.h> #include <SPIFFS.h>
#include <nvs.h>
// SSID & password now stored in NV storage - these are still the default values. // SSID & password now stored in NV storage - these are still the default values.
//#define AP_SSID "Afterburner" //#define AP_SSID "Afterburner"
@ -323,6 +324,9 @@ void setup() {
digitalWrite(GPIOout1_pin, LOW); digitalWrite(GPIOout1_pin, LOW);
digitalWrite(GPIOout2_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 // initialise TelnetSpy (port 23) as well as Serial to 115200
// Serial is the usual USB connection to a PC // Serial is the usual USB connection to a PC
// DO THIS BEFORE WE TRY AND SEND DEBUG INFO! // 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("Board revision: V%.1f\r\n", float(BoardRevision) * 0.1);
DebugPort.printf("ESP32 IDF Version: %s\r\n", esp_get_idf_version()); 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 // Initialize SPIFFS
if(!SPIFFS.begin(true)){ if(!SPIFFS.begin(true)){
@ -1330,7 +1335,7 @@ bool isCyclicActive()
void setupGPIO() void setupGPIO()
{ {
if(BoardRevision) { if(BoardRevision == 10 || BoardRevision == 20 || BoardRevision == 21) {
// some special considerations for GPIO inputs, depending upon PCB hardware // 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. // 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). // 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); GPIOalg.begin(GPIOalg_pin, algMode);
} }
else { 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); GPIOin.begin(0, 0, GPIOinNone, LOW);
GPIOout.begin(0, 0, GPIOoutNone); GPIOout.begin(0, 0, GPIOoutNone);
GPIOalg.begin(ADC1_CHANNEL_5, GPIOalgNone); GPIOalg.begin(ADC1_CHANNEL_5, GPIOalgNone);
@ -1379,10 +1384,14 @@ bool toggleGPIOout(int channel)
return false; 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); if(GPIOout.getMode() != GPIOoutNone) {
GPIOout.setState(channel, state); DebugPort.printf("setGPIO: Output #%d = %d\r\n", channel+1, state);
GPIOout.setState(channel, state);
return true;
}
return false;
} }
bool getGPIOout(int channel) bool getGPIOout(int channel)

View file

@ -52,7 +52,29 @@
#include "fonts/MidiFont.h" #include "fonts/MidiFont.h"
#include "../Protocol/Protocol.h" #include "../Protocol/Protocol.h"
#include "fonts/Arial.h" #include "fonts/Arial.h"
#include <SPIFFS.h>
#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/ // 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() CScreenManager::CScreenManager()
{ {
@ -249,7 +379,10 @@ CScreenManager::begin(bool bNoClock)
// replace adafruit splash screen // replace adafruit splash screen
_pDisplay->clearDisplay(); _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); _pDisplay->setCursor(90, 56);
CTransientFont AF(*_pDisplay, &segoeUI_Italic_7ptFontInfo); // temporarily use a midi font CTransientFont AF(*_pDisplay, &segoeUI_Italic_7ptFontInfo); // temporarily use a midi font
_pDisplay->setTextColor(WHITE); _pDisplay->setTextColor(WHITE);
@ -269,7 +402,8 @@ CScreenManager::begin(bool bNoClock)
if(!bNoClock) if(!bNoClock)
menuloop.push_back(new CClockScreen(*_pDisplay, *this)); // clock menuloop.push_back(new CClockScreen(*_pDisplay, *this)); // clock
menuloop.push_back(new CPrimingScreen(*_pDisplay, *this)); // mode / priming 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)); menuloop.push_back(new CMenuTrunkScreen(*_pDisplay, *this));
_Screens.push_back(menuloop); _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 CThermostatModeScreen(*_pDisplay, *this)); // thermostat settings screen
menuloop.push_back(new CHomeMenuSelScreen(*_pDisplay, *this)); // Home menu 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 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); _Screens.push_back(menuloop);
// create System Settings screens loop // create System Settings screens loop
@ -630,4 +765,5 @@ CScreenManager::_dim(bool state)
{ {
_bDimmed = state; _bDimmed = state;
_pDisplay->dim(state); _pDisplay->dim(state);
} }

View file

@ -46,7 +46,7 @@ class CScreenManager {
void _dim(bool state); void _dim(bool state);
public: public:
enum eUIMenuSets { RootMenuLoop, TimerMenuLoop, TuningMenuLoop, UserSettingsLoop, SystemSettingsLoop, BranchMenu }; 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, enum eUITimerMenus { TimerOverviewUI, Timer1UI, Timer2UI, Timer3UI, Timer4UI, Timer5UI, Timer6UI, Timer7UI,
Timer8UI, Timer9UI, Timer10UI, Timer11UI, Timer12UI, Timer13UI, Timer14UI }; Timer8UI, Timer9UI, Timer10UI, Timer11UI, Timer12UI, Timer13UI, Timer14UI };
enum eUITuningMenus { MixtureUI, HeaterSettingsUI, FuelCalUI }; enum eUITuningMenus { MixtureUI, HeaterSettingsUI, FuelCalUI };

View file

@ -50,12 +50,13 @@
// a reliable read. // a reliable read.
// //
// Input state truth table // Input state truth table
// GPIO26 GPIO33 // GPIO25 GPIO26 GPIO33
// ------ ------ // ------ ------ ------
// V1.0 HIGH HIGH // V1.0 HIGH HIGH HIGH
// unmodified V2.0 HIGH LOW // unmodified V2.0 LOW HIGH LOW
// modified V2.0 LOW HIGH // modified V2.0 LOW LOW HIGH
// V2.1 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"); DebugPort.println("Board detect: Virgin system - attempting to detect revision");
pinMode(25, INPUT_PULLUP);
pinMode(33, INPUT_PULLUP); pinMode(33, INPUT_PULLUP);
pinMode(26, INPUT_PULLUP); pinMode(26, INPUT_PULLUP);
// there is a 100nF capacitor across the analogue input, allow that to charge before testing // there is a 100nF capacitor across the analogue input, allow that to charge before testing
delay(100); delay(100);
int pin25 = digitalRead(25);
int pin33 = digitalRead(33); int pin33 = digitalRead(33);
int pin26 = digitalRead(26); int pin26 = digitalRead(26);
if(pin33 == HIGH && pin26 == HIGH) { if((pin33 == HIGH) && (pin26 == HIGH) && (pin25 == HIGH)) {
revision = 10; revision = 10;
DebugPort.println("Board detect: digital input test reveals V1.x PCB"); 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; revision = 20;
DebugPort.println("Board detect: digital input test reveals V2.0 PCB"); 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; revision = 21;
DebugPort.println("Board detect: digital input test reveals V2.1 PCB"); 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 { else {
DebugPort.println("Board detect: digital input test failed to detect a valid combination!!!"); DebugPort.println("Board detect: digital input test failed to detect a valid combination!!!");
} }
pinMode(33, INPUT); // revert to normal inputs (remove pull ups) pinMode(33, INPUT); // revert to normal inputs (remove pull ups)
pinMode(26, INPUT); pinMode(26, INPUT);
pinMode(25, INPUT); // revert to normal inputs (remove pull ups)
//store the detected revision //store the detected revision
if(revision) { if(revision) {

View file

@ -68,7 +68,7 @@ const char* getVersionStr();
extern const char* getVersionDate(); extern const char* getVersionDate();
extern int getBoardRevision(); extern int getBoardRevision();
extern void setupGPIO(); extern void setupGPIO();
extern void setGPIOout(int channel, bool state); extern bool setGPIOout(int channel, bool state);
extern bool getGPIOout(int channel); extern bool getGPIOout(int channel);
extern bool toggleGPIOout(int channel); extern bool toggleGPIOout(int channel);
extern void feedWatchdog(); extern void feedWatchdog();

View file

@ -49,6 +49,8 @@ extern const char* updateIndex;
extern const char* formatDoneContent; extern const char* formatDoneContent;
extern const char* rebootIndex; extern const char* rebootIndex;
extern void storeSplashScreenFile();
sBrowserUpload BrowserUpload; sBrowserUpload BrowserUpload;
WebServer server(80); WebServer server(80);
WebSocketsServer webSocket = WebSocketsServer(81); WebSocketsServer webSocket = WebSocketsServer(81);
@ -693,6 +695,7 @@ void onUploadCompletion()
// completion functionality // completion functionality
if(BrowserUpload.isSPIFFSupload()) { if(BrowserUpload.isSPIFFSupload()) {
if(BrowserUpload.isOK()) { if(BrowserUpload.isOK()) {
storeSplashScreenFile();
DebugPort.println("WEB: SPIFFS OK"); DebugPort.println("WEB: SPIFFS OK");
server.send(200, "text/plain", "OK - File uploaded to SPIFFS"); server.send(200, "text/plain", "OK - File uploaded to SPIFFS");
// javascript reselects the /update page! // javascript reselects the /update page!