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 <esp_spiffs.h>
#include <SPIFFS.h>
#include <nvs.h>
// 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)

View file

@ -52,7 +52,29 @@
#include "fonts/MidiFont.h"
#include "../Protocol/Protocol.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/
@ -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);
}
}

View file

@ -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 };

View file

@ -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) {

View file

@ -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();

View file

@ -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!