From 4c383e9cd39a5ac8a4504c86b1cf156be2934de8 Mon Sep 17 00:00:00 2001 From: Thomas Ballmann Date: Mon, 10 Feb 2020 23:14:54 +0100 Subject: [PATCH] first working version --- .gitignore | 2 +- .vscode/settings.json | 9 + include/cloud.h | 2 + include/device.h | 15 ++ include/display.h | 13 +- include/displayDemo.h | 21 ++ platformio.ini | 7 + src/cloud.cpp | 76 +++--- src/device.cpp | 81 +++++++ src/display.cpp | 546 +++++------------------------------------- src/displayDemo.cpp | 534 +++++++++++++++++++++++++++++++++++++++++ src/main.cpp | 23 +- src/wlan.cpp | 64 +++-- 13 files changed, 828 insertions(+), 565 deletions(-) create mode 100644 .vscode/settings.json create mode 100644 include/device.h create mode 100644 include/displayDemo.h create mode 100644 src/device.cpp create mode 100644 src/displayDemo.cpp diff --git a/.gitignore b/.gitignore index 89cc49c..69107a2 100644 --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,4 @@ .vscode/.browse.c_cpp.db* .vscode/c_cpp_properties.json .vscode/launch.json -.vscode/ipch +.vscode/ipch \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..79d4762 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,9 @@ +{ + "files.associations": { + "*.tcc": "cpp", + "fstream": "cpp", + "istream": "cpp", + "ostream": "cpp", + "sstream": "cpp" + } +} \ No newline at end of file diff --git a/include/cloud.h b/include/cloud.h index b95be11..59670cb 100644 --- a/include/cloud.h +++ b/include/cloud.h @@ -1,6 +1,8 @@ #ifndef CLOUD_H #define CLOUD_H +#define config_PullServer "http://paperdash.sonic.da-tom.com/gateway.php/" + void setupCloud(); void loopCloud(); diff --git a/include/device.h b/include/device.h new file mode 100644 index 0000000..04af7ef --- /dev/null +++ b/include/device.h @@ -0,0 +1,15 @@ +#ifndef DEVICE_H +#define DEVICE_H + +#include +#include + + +void setupDevice(); +void loopDevice(); + +void deviceSetSleepInterval(long interval); +long deviceGetSleepInterval(); + + +#endif \ No newline at end of file diff --git a/include/display.h b/include/display.h index 284c6ee..12f87f1 100644 --- a/include/display.h +++ b/include/display.h @@ -7,17 +7,10 @@ void setupDisplay(); -void updateDisplay_Neu(const unsigned char *bitmap); -void drawBitmaps640x384(); -void helloWorld(); -void helloFullScreenPartialMode(); -void helloArduino(); -void helloEpaper(); -void showFont(const char name[], const GFXfont* f); -void drawFont(const char name[], const GFXfont* f); -void drawBitmaps(); +void displayOpenFramebuffer(); +void displayWriteFramebuffer(int offset, uint8_t buff[], int c); +void displayFlushFramebuffer(); -void deepSleepTest(); #endif \ No newline at end of file diff --git a/include/displayDemo.h b/include/displayDemo.h new file mode 100644 index 0000000..0b91fbf --- /dev/null +++ b/include/displayDemo.h @@ -0,0 +1,21 @@ +#ifndef DISPLAY_DISPLAY_H +#define DISPLAY_DISPLAY_H + +#include +#include + + +void setupDisplayDemo(); + +void drawBitmaps640x384(); +void helloWorld(); +void helloFullScreenPartialMode(); +void helloArduino(); +void helloEpaper(); +void showFont(const char name[], const GFXfont* f); +void drawFont(const char name[], const GFXfont* f); +void drawBitmaps(); + +void deepSleepTest(); + +#endif \ No newline at end of file diff --git a/platformio.ini b/platformio.ini index 6881a77..24e1a8e 100644 --- a/platformio.ini +++ b/platformio.ini @@ -4,7 +4,14 @@ board = lolin32 framework = arduino ;upload_port = 192.168.178.60 + +# lolin32 upload_speed = 921600 +monitor_speed = 115200 + +# lolin32 lite +upload_speed = 115200 +upload_port = /dev/cu.wchusbserial1460 lib_deps = GxEPD2@~1.2.4 diff --git a/src/cloud.cpp b/src/cloud.cpp index 35f1882..1728b9a 100644 --- a/src/cloud.cpp +++ b/src/cloud.cpp @@ -1,54 +1,56 @@ #include #include +#include + -//#include "uuid.h" -//#include "wlan.h" -//#include "ota.h" #include "display.h" -#include +#include "device.h" -// SMART SIGN CONFIG ======== -#define config_PullServer "http://smart-sign-server/satellite/get-data" // pull server address -RTC_DATA_ATTR long config_DeepSleepInterval = 300; // 5 min pull intervall -String config_UUID = ""; + +// TODO SMART SIGN CONFIG ======== +#define config_PullServer "http://paperdash.sonic.da-tom.com/gateway.php/" // pull server address +String config_UUID = "22805938-2280-8022-3822-385980225980"; // TODO // SMART SIGN CONFIG ======== // runtime data const char *setting_HeaderKeys[] = { - "DeepSleepInterval" // update deep sleep interval - , - "DisplayImage" // images for display... - , - "UpdateFirmware" // execute firmware update + // update deep sleep interval + "DeepSleepInterval", + // execute firmware update url + "UpdateFirmware" }; -long pullCount = 0; -#include -#define FRAME_BUFFERBUFFE_SIZE GxEPD2_750::WIDTH *GxEPD2_750::HEIGHT / 8 -PROGMEM unsigned char displayImageBuffer[FRAME_BUFFERBUFFE_SIZE]; +//#include +//#define FRAME_BUFFERBUFFE_SIZE GxEPD2_750::WIDTH *GxEPD2_750::HEIGHT / 8 +//PROGMEM unsigned char displayImageBuffer[FRAME_BUFFERBUFFE_SIZE]; HTTPClient http; +void pullData(); + + void setupCloud() { + Serial.println("setup cloud"); + http.useHTTP10(true); // http1.1 chunked übertragung funktioniert irgendwie nicht http.setTimeout(7000); http.collectHeaders(setting_HeaderKeys, sizeof(setting_HeaderKeys) / sizeof(char *)); -} + Serial.println("setup cloud - done"); +} void loopCloud() { - + pullData(); } - /** * 1. neue config daten über den http header laden * 2. neues bild vom server laden und anzeigen sofern vorhanden * @return bool true on new data to display */ -bool pullData() +void pullData() { String pullUrl = String(config_PullServer) + "/" + config_UUID; // + "?deep-sleep=" + String(config_DeepSleepInterval) + "&wakeup=" + getWakeupReason(); @@ -64,20 +66,20 @@ bool pullData() { // update poll interval String DeepSleepInterval = http.header("DeepSleepInterval"); - if (DeepSleepInterval.toInt() == 0) + if (false && DeepSleepInterval.toInt() == 0) { - // TODO disable deep sleep - config_DeepSleepInterval = DeepSleepInterval.toInt(); + // disable deep sleep + Serial.println("###### deep sleep disabled"); + deviceSetSleepInterval(0); } - else if (DeepSleepInterval.toInt() > 5 && DeepSleepInterval.toInt() != config_DeepSleepInterval) + else if (DeepSleepInterval.toInt() > 5 && DeepSleepInterval.toInt() != deviceGetSleepInterval()) { - // TODO + // update config Serial.println("###### config update"); - Serial.println(" set deep sleep interval from: " + String(config_DeepSleepInterval) + " to " + DeepSleepInterval); + Serial.println(" set deep sleep interval from: " + String(deviceGetSleepInterval()) + " to " + DeepSleepInterval); Serial.println("###### config update"); - config_DeepSleepInterval = DeepSleepInterval.toInt(); - //setupDeepSleep(); + deviceSetSleepInterval(DeepSleepInterval.toInt()); } @@ -88,10 +90,9 @@ bool pullData() Serial.println("TODO update firmware..."); } - if (httpCode == HTTP_CODE_OK) { - // TODO update image + // update image // get lenght of document (is -1 when Server sends no Content-Length header) int len = http.getSize(); @@ -103,13 +104,13 @@ bool pullData() WiFiClient *stream = http.getStreamPtr(); // reset image buffer - memset(displayImageBuffer, 0, sizeof(displayImageBuffer)); + //memset(displayImageBuffer, 0, sizeof(displayImageBuffer)); int imageBufferOffset = 0; + displayOpenFramebuffer(); // read all data from server while (http.connected() && (len > 0 || len == -1)) { - // get available data size size_t size = stream->available(); @@ -118,6 +119,9 @@ bool pullData() // read up to 128 byte int c = stream->readBytes(buff, ((size > sizeof(buff)) ? sizeof(buff) : size)); + displayWriteFramebuffer(imageBufferOffset, buff, c); + imageBufferOffset += c; +/* for (int i = 0; i < c; i++) { // write to display buffer @@ -140,6 +144,7 @@ bool pullData() break; } } + */ if (len > 0) { @@ -150,9 +155,8 @@ bool pullData() delay(1); } - return true; + // done + displayFlushFramebuffer(); } } - - return false; } \ No newline at end of file diff --git a/src/device.cpp b/src/device.cpp new file mode 100644 index 0000000..b0c5158 --- /dev/null +++ b/src/device.cpp @@ -0,0 +1,81 @@ +#include "device.h" + +#define uS_TO_S_FACTOR 1000000 /* Conversion factor for micro seconds to seconds */ +RTC_DATA_ATTR int bootCount = 0; +RTC_DATA_ATTR long config_DeepSleepInterval = 0; + + +// private methods +void sleepDevice(); +String getWakeupReason(); + + +/** + * setup deep sleep mode + */ +void setupDevice() +{ + // increment boot number and print it every reboot + //bootCount++; + + // config wakeup timer + deviceSetSleepInterval(300); +} + + +void loopDevice() +{ + if (config_DeepSleepInterval > 0) + { + sleepDevice(); + // device stop here + } +} + + +void sleepDevice() +{ + Serial.println("Going to sleep now"); + Serial.flush(); + + esp_sleep_enable_timer_wakeup(config_DeepSleepInterval * uS_TO_S_FACTOR); + esp_deep_sleep_start(); +} + + +void deviceSetSleepInterval(long interval) +{ + config_DeepSleepInterval = interval; +} + + +long deviceGetSleepInterval() +{ + return config_DeepSleepInterval; +} + +String getWakeupReason() +{ + esp_sleep_wakeup_cause_t wakeup_reason; + wakeup_reason = esp_sleep_get_wakeup_cause(); + + //return String(wakeup_reason); + + switch (wakeup_reason) + { + case 1: + return String("Wakeup caused by external signal using RTC_IO"); + case 2: + return String("Wakeup caused by external signal using RTC_CNTL"); + case 3: + return String("Wakeup caused by timer"); + case 4: + return String("Wakeup caused by touchpad"); + case 5: + return String("Wakeup caused by ULP program"); + default: + return String("Wakeup was not caused by deep sleep: " + String(wakeup_reason)); + } + + return String("unkown"); +} \ No newline at end of file diff --git a/src/display.cpp b/src/display.cpp index 26e2b89..8d40c86 100644 --- a/src/display.cpp +++ b/src/display.cpp @@ -3,7 +3,7 @@ // mapping suggestion for ESP32, e.g. LOLIN32, see .../variants/.../pins_arduino.h for your board // NOTE: there are variants with different pins for SPI ! CHECK SPI PINS OF YOUR BOARD -// BUSY -> 4, RST -> 16, DC -> 17, CS -> SS(5), CLK -> SCK(18), DIN -> MOSI(23), GND -> GND, 3.3V -> 3.3V +// BUSY -> 4, RST -> 16, DC -> 17, CS -> SS(5), CLK -> (18), DIN -> MOSI(23), GND -> GND, 3.3V -> 3.3V // mapping of Waveshare Universal e-Paper Raw Panel Driver Shield for Arduino / NUCLEO // BUSY -> 7, RST -> 8, DC -> 9, CS-> 10, CLK -> 13, DIN -> 11 @@ -12,325 +12,105 @@ // enable or disable GxEPD2_GFX base class #define ENABLE_GxEPD2_GFX 0 -GxEPD2_BW display(GxEPD2_750(/*CS=5*/ 5, /*DC=*/0, /*RST=*/2, /*BUSY=*/15)); -#include "bitmaps/Bitmaps640x384.h" // 7.5" b/w +GxEPD2_BW display(GxEPD2_750(/*CS=*/ 5, /*DC=*/ 17, /*RST=*/ 16, /*BUSY=*/ 4)); +uint8_t _buffer[(GxEPD2_750::WIDTH / 8) * GxEPD2_750::HEIGHT]; void setupDisplay() { - //Serial.begin(115200); - //Serial.println(); Serial.println("setupDisplay"); delay(100); display.init(115200); - // first update should be full refresh - helloWorld(); - delay(1000); - // partial refresh mode can be used to full screen, - // effective if display panel hasFastPartialUpdate - helloFullScreenPartialMode(); - delay(1000); - helloArduino(); - delay(1000); - helloEpaper(); - delay(1000); - //helloValue(123.9, 1); - //delay(1000); - showFont("FreeMonoBold9pt7b", &FreeMonoBold9pt7b); - delay(1000); - drawBitmaps(); - display.powerOff(); - deepSleepTest(); Serial.println("setup done"); } -void updateDisplay_Neu(const unsigned char *bitmap) -{ - Serial.println("Update Display #"); - - display.setFullWindow(); - - //drawBitmaps640x384(); - - display.firstPage(); - do - { - display.fillScreen(GxEPD_WHITE); - //display.drawBitmap(0, 0, bitmap, display.epd2.WIDTH, display.epd2.HEIGHT, GxEPD_BLACK); - display.drawInvertedBitmap(0, 0, bitmap, display.epd2.WIDTH, display.epd2.HEIGHT, GxEPD_BLACK); - } while (display.nextPage()); -} - - - - -// note for partial update window and setPartialWindow() method: -// partial update window size and position is on byte boundary in physical x direction -// the size is increased in setPartialWindow() if x or w are not multiple of 8 for even rotation, y or h for odd rotation -// see also comment in GxEPD2_BW.h, GxEPD2_3C.h or GxEPD2_GFX.h for method setPartialWindow() - -const char HelloWorld[] = "Hello World!"; -const char HelloArduino[] = "Hello Arduino!"; -const char HelloEpaper[] = "Hello E-Paper!"; - -void helloWorld() +void displayOpenFramebuffer() { - //Serial.println("helloWorld"); - display.setRotation(1); - display.setFont(&FreeMonoBold9pt7b); - display.setTextColor(GxEPD_BLACK); - int16_t tbx, tby; - uint16_t tbw, tbh; - display.getTextBounds(HelloWorld, 0, 0, &tbx, &tby, &tbw, &tbh); - // center bounding box by transposition of origin: - uint16_t x = ((display.width() - tbw) / 2) - tbx; - uint16_t y = ((display.height() - tbh) / 2) - tby; - display.setFullWindow(); - display.firstPage(); - do - { - display.fillScreen(GxEPD_WHITE); - display.setCursor(x, y); - display.print(HelloWorld); - } while (display.nextPage()); - //Serial.println("helloWorld done"); + memset(_buffer, 0, sizeof(_buffer)); + //display.setFullWindow(); + //display.firstPage(); + //display.fillScreen(GxEPD_WHITE); } -void helloWorldForDummies() +// TODO +void displayWriteFramebuffer(int offset, uint8_t bitmap[], int c) { - //Serial.println("helloWorld"); - const char text[] = "Hello World!"; - // most e-papers have width < height (portrait) as native orientation, especially the small ones - // in GxEPD2 rotation 0 is used for native orientation (most TFT libraries use 0 fix for portrait orientation) - // set rotation to 1 (rotate right 90 degrees) to have enough space on small displays (landscape) - display.setRotation(1); - // select a suitable font in Adafruit_GFX - display.setFont(&FreeMonoBold9pt7b); - // on e-papers black on white is more pleasant to read - display.setTextColor(GxEPD_BLACK); - // Adafruit_GFX has a handy method getTextBounds() to determine the boundary box for a text for the actual font - int16_t tbx, tby; - uint16_t tbw, tbh; // boundary box window - display.getTextBounds(text, 0, 0, &tbx, &tby, &tbw, &tbh); // it works for origin 0, 0, fortunately (negative tby!) - // center bounding box by transposition of origin: - uint16_t x = ((display.width() - tbw) / 2) - tbx; - uint16_t y = ((display.height() - tbh) / 2) - tby; - // full window mode is the initial mode, set it anyway - display.setFullWindow(); - // here we use paged drawing, even if the processor has enough RAM for full buffer - // so this can be used with any supported processor board. - // the cost in code overhead and execution time penalty is marginal - // tell the graphics class to use paged drawing mode - display.firstPage(); - do + for (int i = 0; i < c; i++) { - // this part of code is executed multiple times, as many as needed, - // in case of full buffer it is executed once - // IMPORTANT: each iteration needs to draw the same, to avoid strange effects - // use a copy of values that might change, don't read e.g. from analog or pins in the loop! - display.fillScreen(GxEPD_WHITE); // set the background to white (fill the buffer with value for white) - display.setCursor(x, y); // set the postition to start printing text - display.print(text); // print some text - // end of part executed multiple times + _buffer[offset] = bitmap[i]; + offset++; } - // tell the graphics class to transfer the buffer content (page) to the controller buffer - // the graphics class will command the controller to refresh to the screen when the last page has been transferred - // returns true if more pages need be drawn and transferred - // returns false if the last page has been transferred and the screen refreshed for panels without fast partial update - // returns false for panels with fast partial update when the controller buffer has been written once more, to make the differential buffers equal - // (for full buffered with fast partial update the (full) buffer is just transferred again, and false returned) - while (display.nextPage()); - //Serial.println("helloWorld done"); -} -void helloFullScreenPartialMode() -{ - //Serial.println("helloFullScreenPartialMode"); - const char fullscreen[] = "full screen update"; - const char fpm[] = "fast partial mode"; - const char spm[] = "slow partial mode"; - const char npm[] = "no partial mode"; - display.setPartialWindow(0, 0, display.width(), display.height()); - display.setRotation(1); - display.setFont(&FreeMonoBold9pt7b); - display.setTextColor(GxEPD_BLACK); - const char *updatemode; - if (display.epd2.hasFastPartialUpdate) - { - updatemode = fpm; - } - else if (display.epd2.hasPartialUpdate) + /* + //if (offset + sizeof(*bitmap) <= sizeof(_buffer)) + if (true) { - updatemode = spm; + memcpy((&_buffer) + offset, bitmap, 128); } else { - updatemode = npm; + Serial.println("!!!!! displayWriteFramebuffer overflow"); } - // do this outside of the loop - int16_t tbx, tby; - uint16_t tbw, tbh; - // center update text - display.getTextBounds(fullscreen, 0, 0, &tbx, &tby, &tbw, &tbh); - uint16_t utx = ((display.width() - tbw) / 2) - tbx; - uint16_t uty = ((display.height() / 4) - tbh / 2) - tby; - // center update mode - display.getTextBounds(updatemode, 0, 0, &tbx, &tby, &tbw, &tbh); - uint16_t umx = ((display.width() - tbw) / 2) - tbx; - uint16_t umy = ((display.height() * 3 / 4) - tbh / 2) - tby; - // center HelloWorld - display.getTextBounds(HelloWorld, 0, 0, &tbx, &tby, &tbw, &tbh); - uint16_t hwx = ((display.width() - tbw) / 2) - tbx; - uint16_t hwy = ((display.height() - tbh) / 2) - tby; - display.firstPage(); - do - { - display.fillScreen(GxEPD_WHITE); - display.setCursor(hwx, hwy); - display.print(HelloWorld); - display.setCursor(utx, uty); - display.print(fullscreen); - display.setCursor(umx, umy); - display.print(updatemode); - } while (display.nextPage()); - //Serial.println("helloFullScreenPartialMode done"); + */ } -void helloArduino() -{ - //Serial.println("helloArduino"); - display.setRotation(1); - display.setFont(&FreeMonoBold9pt7b); - display.setTextColor(display.epd2.hasColor ? GxEPD_RED : GxEPD_BLACK); - int16_t tbx, tby; - uint16_t tbw, tbh; - // align with centered HelloWorld - display.getTextBounds(HelloWorld, 0, 0, &tbx, &tby, &tbw, &tbh); - uint16_t x = ((display.width() - tbw) / 2) - tbx; - // height might be different - display.getTextBounds(HelloArduino, 0, 0, &tbx, &tby, &tbw, &tbh); - uint16_t y = ((display.height() / 4) - tbh / 2) - tby; // y is base line! - // make the window big enough to cover (overwrite) descenders of previous text - uint16_t wh = FreeMonoBold9pt7b.yAdvance; - uint16_t wy = (display.height() / 4) - wh / 2; - display.setPartialWindow(0, wy, display.width(), wh); - display.firstPage(); - do - { - display.fillScreen(GxEPD_WHITE); - //display.drawRect(x, y - tbh, tbw, tbh, GxEPD_BLACK); - display.setCursor(x, y); - display.print(HelloArduino); - } while (display.nextPage()); - delay(1000); - //Serial.println("helloArduino done"); -} -void helloEpaper() +void displayFlushFramebuffer() { - //Serial.println("helloEpaper"); - display.setRotation(1); - display.setFont(&FreeMonoBold9pt7b); - display.setTextColor(display.epd2.hasColor ? GxEPD_RED : GxEPD_BLACK); - int16_t tbx, tby; - uint16_t tbw, tbh; - // align with centered HelloWorld - display.getTextBounds(HelloWorld, 0, 0, &tbx, &tby, &tbw, &tbh); - uint16_t x = ((display.width() - tbw) / 2) - tbx; - // height might be different - display.getTextBounds(HelloEpaper, 0, 0, &tbx, &tby, &tbw, &tbh); - uint16_t y = (display.height() * 3 / 4) + tbh / 2; // y is base line! - // make the window big enough to cover (overwrite) descenders of previous text - uint16_t wh = FreeMonoBold9pt7b.yAdvance; - uint16_t wy = (display.height() * 3 / 4) - wh / 2; - display.setPartialWindow(0, wy, display.width(), wh); + Serial.println("displayFlushFramebuffer"); + display.setRotation(0); + display.setFullWindow(); display.firstPage(); - do - { - display.fillScreen(GxEPD_WHITE); - display.setCursor(x, y); - display.print(HelloEpaper); - } while (display.nextPage()); - //Serial.println("helloEpaper done"); + display.fillScreen(GxEPD_WHITE); + display.drawInvertedBitmap(0, 0, _buffer, display.epd2.WIDTH, display.epd2.HEIGHT, GxEPD_BLACK); + display.nextPage(); } -#if defined(ESP8266) || defined(ESP32) -#include -#define PrintString StreamString -#else -class PrintString : public Print, public String -{ -public: - size_t write(uint8_t data) override - { - return concat(char(data)); - }; -}; -#endif -void helloValue(double v, int digits) +/** + * @todo fertigstellen + */ +void displayWriteFramebuffer__(int offset, uint8_t bitmap[]) { - //Serial.println("helloValue"); - display.setRotation(1); - display.setFont(&FreeMonoBold9pt7b); - display.setTextColor(display.epd2.hasColor ? GxEPD_RED : GxEPD_BLACK); - PrintString valueString; - valueString.print(v, digits); - int16_t tbx, tby; - uint16_t tbw, tbh; - display.getTextBounds(valueString, 0, 0, &tbx, &tby, &tbw, &tbh); - uint16_t x = ((display.width() - tbw) / 2) - tbx; - uint16_t y = (display.height() * 3 / 4) + tbh / 2; // y is base line! - // show what happens, if we use the bounding box for partial window - uint16_t wx = (display.width() - tbw) / 2; - uint16_t wy = (display.height() * 3 / 4) - tbh / 2; - display.setPartialWindow(wx, wy, tbw, tbh); - display.firstPage(); - do - { - display.fillScreen(GxEPD_WHITE); - display.setCursor(x, y); - display.print(valueString); - } while (display.nextPage()); - delay(2000); - // make the partial window big enough to cover the previous text - uint16_t ww = tbw; // remember window width - display.getTextBounds(HelloEpaper, 0, 0, &tbx, &tby, &tbw, &tbh); - // adjust, because HelloEpaper was aligned, not centered (could calculate this to be precise) - ww = max(ww, uint16_t(tbw + 12)); // 12 seems ok - wx = (display.width() - tbw) / 2; - // make the window big enough to cover (overwrite) descenders of previous text - uint16_t wh = FreeMonoBold9pt7b.yAdvance; - wy = (display.height() * 3 / 4) - wh / 2; - display.setPartialWindow(wx, wy, ww, wh); - // alternately use the whole width for partial window - //display.setPartialWindow(0, wy, display.width(), wh); - display.firstPage(); - do + // taken from Adafruit_GFX.cpp, modified + int16_t w = display.epd2.WIDTH; + int16_t h = display.epd2.HEIGHT; + + int16_t byteWidth = (w + 7) / 8; // Bitmap scanline pad = whole byte + uint8_t byte = 0; + for (int16_t j = 0; j < h; j++) { - display.fillScreen(GxEPD_WHITE); - display.setCursor(x, y); - display.print(valueString); - } while (display.nextPage()); - //Serial.println("helloValue done"); + for (int16_t i = 0; i < w; i++ ) + { + if (i & 7) byte <<= 1; + else + { + byte = pgm_read_byte(&bitmap[j * byteWidth + i / 8]); + } + + if (!(byte & 0x80)) + { + display.drawPixel(0 + i, 0 + j, GxEPD_BLACK); + } + } + } } -void deepSleepTest() + + +void printSplash() { - //Serial.println("deepSleepTest"); - const char hibernating[] = "hibernating ..."; - const char wokeup[] = "woke up"; - const char from[] = "from deep sleep"; - const char again[] = "again"; + const char Hello[] = "Hello Paperdash!"; + display.setRotation(1); display.setFont(&FreeMonoBold9pt7b); display.setTextColor(GxEPD_BLACK); int16_t tbx, tby; uint16_t tbw, tbh; - // center text - display.getTextBounds(hibernating, 0, 0, &tbx, &tby, &tbw, &tbh); + display.getTextBounds(Hello, 0, 0, &tbx, &tby, &tbw, &tbh); + // center bounding box by transposition of origin: uint16_t x = ((display.width() - tbw) / 2) - tbx; uint16_t y = ((display.height() - tbh) / 2) - tby; display.setFullWindow(); @@ -339,212 +119,6 @@ void deepSleepTest() { display.fillScreen(GxEPD_WHITE); display.setCursor(x, y); - display.print(hibernating); - } while (display.nextPage()); - display.hibernate(); - delay(5000); - display.getTextBounds(wokeup, 0, 0, &tbx, &tby, &tbw, &tbh); - uint16_t wx = (display.width() - tbw) / 2; - uint16_t wy = (display.height() / 3) + tbh / 2; // y is base line! - display.getTextBounds(from, 0, 0, &tbx, &tby, &tbw, &tbh); - uint16_t fx = (display.width() - tbw) / 2; - uint16_t fy = (display.height() * 2 / 3) + tbh / 2; // y is base line! - display.firstPage(); - do - { - display.fillScreen(GxEPD_WHITE); - display.setCursor(wx, wy); - display.print(wokeup); - display.setCursor(fx, fy); - display.print(from); - } while (display.nextPage()); - delay(5000); - display.getTextBounds(hibernating, 0, 0, &tbx, &tby, &tbw, &tbh); - uint16_t hx = (display.width() - tbw) / 2; - uint16_t hy = (display.height() / 3) + tbh / 2; // y is base line! - display.getTextBounds(again, 0, 0, &tbx, &tby, &tbw, &tbh); - uint16_t ax = (display.width() - tbw) / 2; - uint16_t ay = (display.height() * 2 / 3) + tbh / 2; // y is base line! - display.firstPage(); - do - { - display.fillScreen(GxEPD_WHITE); - display.setCursor(hx, hy); - display.print(hibernating); - display.setCursor(ax, ay); - display.print(again); - } while (display.nextPage()); - display.hibernate(); - //Serial.println("deepSleepTest done"); -} - -void showBox(uint16_t x, uint16_t y, uint16_t w, uint16_t h, bool partial) -{ - //Serial.println("showBox"); - display.setRotation(1); - if (partial) - { - display.setPartialWindow(x, y, w, h); - } - else - { - display.setFullWindow(); - } - display.firstPage(); - do - { - display.fillScreen(GxEPD_WHITE); - display.fillRect(x, y, w, h, GxEPD_BLACK); - } while (display.nextPage()); - //Serial.println("showBox done"); -} - -void drawCornerTest() -{ - display.setFullWindow(); - display.setFont(&FreeMonoBold9pt7b); - display.setTextColor(GxEPD_BLACK); - for (uint16_t r = 0; r <= 4; r++) - { - display.setRotation(r); - display.firstPage(); - do - { - display.fillScreen(GxEPD_WHITE); - display.fillRect(0, 0, 8, 8, GxEPD_BLACK); - display.fillRect(display.width() - 18, 0, 16, 16, GxEPD_BLACK); - display.fillRect(display.width() - 25, display.height() - 25, 24, 24, GxEPD_BLACK); - display.fillRect(0, display.height() - 33, 32, 32, GxEPD_BLACK); - display.setCursor(display.width() / 2, display.height() / 2); - display.print(display.getRotation()); - } while (display.nextPage()); - delay(2000); - } -} - -void showFont(const char name[], const GFXfont *f) -{ - display.setFullWindow(); - display.setRotation(0); - display.setTextColor(GxEPD_BLACK); - display.firstPage(); - do - { - drawFont(name, f); + display.print(Hello); } while (display.nextPage()); -} - -void drawFont(const char name[], const GFXfont *f) -{ - //display.setRotation(0); - display.fillScreen(GxEPD_WHITE); - display.setTextColor(GxEPD_BLACK); - display.setFont(f); - display.setCursor(0, 0); - display.println(); - display.println(name); - display.println(" !\"#$%&'()*+,-./"); - display.println("0123456789:;<=>?"); - display.println("@ABCDEFGHIJKLMNO"); - display.println("PQRSTUVWXYZ[\\]^_"); - if (display.epd2.hasColor) - { - display.setTextColor(GxEPD_RED); - } - display.println("`abcdefghijklmno"); - display.println("pqrstuvwxyz{|}~ "); -} - -// note for partial update window and setPartialWindow() method: -// partial update window size and position is on byte boundary in physical x direction -// the size is increased in setPartialWindow() if x or w are not multiple of 8 for even rotation, y or h for odd rotation -// see also comment in GxEPD2_BW.h, GxEPD2_3C.h or GxEPD2_GFX.h for method setPartialWindow() -// showPartialUpdate() purposely uses values that are not multiples of 8 to test this - -void showPartialUpdate() -{ - // some useful background - helloWorld(); - // use asymmetric values for test - uint16_t box_x = 10; - uint16_t box_y = 15; - uint16_t box_w = 70; - uint16_t box_h = 20; - uint16_t cursor_y = box_y + box_h - 6; - float value = 13.95; - uint16_t incr = display.epd2.hasFastPartialUpdate ? 1 : 3; - display.setFont(&FreeMonoBold9pt7b); - display.setTextColor(GxEPD_BLACK); - // show where the update box is - for (uint16_t r = 0; r < 4; r++) - { - display.setRotation(r); - display.setPartialWindow(box_x, box_y, box_w, box_h); - display.firstPage(); - do - { - display.fillRect(box_x, box_y, box_w, box_h, GxEPD_BLACK); - //display.fillScreen(GxEPD_BLACK); - } while (display.nextPage()); - delay(2000); - display.firstPage(); - do - { - display.fillRect(box_x, box_y, box_w, box_h, GxEPD_WHITE); - } while (display.nextPage()); - delay(1000); - } - //return; - // show updates in the update box - for (uint16_t r = 0; r < 4; r++) - { - display.setRotation(r); - display.setPartialWindow(box_x, box_y, box_w, box_h); - for (uint16_t i = 1; i <= 10; i += incr) - { - display.firstPage(); - do - { - display.fillRect(box_x, box_y, box_w, box_h, GxEPD_WHITE); - display.setCursor(box_x, cursor_y); - display.print(value * i, 2); - } while (display.nextPage()); - delay(500); - } - delay(1000); - display.firstPage(); - do - { - display.fillRect(box_x, box_y, box_w, box_h, GxEPD_WHITE); - } while (display.nextPage()); - delay(1000); - } -} - -void drawBitmaps() -{ - display.setFullWindow(); - - drawBitmaps640x384(); -} - -void drawBitmaps640x384() -{ - const unsigned char *bitmaps[] = - { - Bitmap640x384_1, Bitmap640x384_2}; - - if ((display.epd2.panel == GxEPD2::GDEW075T8) || (display.epd2.panel == GxEPD2::GDEW075Z09)) - { - for (uint16_t i = 0; i < sizeof(bitmaps) / sizeof(char *); i++) - { - display.firstPage(); - do - { - display.fillScreen(GxEPD_WHITE); - display.drawInvertedBitmap(0, 0, bitmaps[i], display.epd2.WIDTH, display.epd2.HEIGHT, GxEPD_BLACK); - } while (display.nextPage()); - delay(2000); - } - } -} +} \ No newline at end of file diff --git a/src/displayDemo.cpp b/src/displayDemo.cpp new file mode 100644 index 0000000..2aacce3 --- /dev/null +++ b/src/displayDemo.cpp @@ -0,0 +1,534 @@ +#include +#include "displayDemo.h" + +// mapping suggestion for ESP32, e.g. LOLIN32, see .../variants/.../pins_arduino.h for your board +// NOTE: there are variants with different pins for SPI ! CHECK SPI PINS OF YOUR BOARD +// BUSY -> 4, RST -> 16, DC -> 17, CS -> SS(5), CLK -> (18), DIN -> MOSI(23), GND -> GND, 3.3V -> 3.3V + +// mapping of Waveshare Universal e-Paper Raw Panel Driver Shield for Arduino / NUCLEO +// BUSY -> 7, RST -> 8, DC -> 9, CS-> 10, CLK -> 13, DIN -> 11 + +// base class GxEPD2_GFX can be used to pass references or pointers to the diplay2 instance as parameter, uses ~1.2k more code +// enable or disable GxEPD2_GFX base class +//#define ENABLE_GxEPD2_GFX 1 +#include "bitmaps/Bitmaps640x384.h" // 7.5" b/w + + +GxEPD2_BW diplay2(GxEPD2_750(/*CS=*/ 5, /*DC=*/ 17, /*RST=*/ 16, /*BUSY=*/ 4)); + + +void setupdiplay2Demo() +{ + Serial.println("setupdiplay2Demo"); + delay(100); + diplay2.init(115200); + + // first update should be full refresh + helloWorld(); + delay(1000); + diplay2.powerOff(); + // partial refresh mode can be used to full screen, + // effective if diplay2 panel hasFastPartialUpdate + helloFullScreenPartialMode(); + delay(1000); + helloArduino(); + delay(1000); + helloEpaper(); + delay(1000); + //helloValue(123.9, 1); + //delay(1000); + showFont("FreeMonoBold9pt7b", &FreeMonoBold9pt7b); + delay(1000); + drawBitmaps(); + + diplay2.powerOff(); + deepSleepTest(); + + Serial.println("setup done"); +} + + + + +// note for partial update window and setPartialWindow() method: +// partial update window size and position is on byte boundary in physical x direction +// the size is increased in setPartialWindow() if x or w are not multiple of 8 for even rotation, y or h for odd rotation +// see also comment in GxEPD2_BW.h, GxEPD2_3C.h or GxEPD2_GFX.h for method setPartialWindow() + +const char HelloWorld[] = "Hello World!"; +const char HelloArduino[] = "Hello Arduino!"; +const char HelloEpaper[] = "Hello E-Paper!"; + +void helloWorld() +{ + //Serial.println("helloWorld"); + diplay2.setRotation(1); + diplay2.setFont(&FreeMonoBold9pt7b); + diplay2.setTextColor(GxEPD_BLACK); + int16_t tbx, tby; + uint16_t tbw, tbh; + diplay2.getTextBounds(HelloWorld, 0, 0, &tbx, &tby, &tbw, &tbh); + // center bounding box by transposition of origin: + uint16_t x = ((diplay2.width() - tbw) / 2) - tbx; + uint16_t y = ((diplay2.height() - tbh) / 2) - tby; + diplay2.setFullWindow(); + diplay2.firstPage(); + do + { + diplay2.fillScreen(GxEPD_WHITE); + diplay2.setCursor(x, y); + diplay2.print(HelloWorld); + } while (diplay2.nextPage()); + //Serial.println("helloWorld done"); +} + +void helloWorldForDummies() +{ + //Serial.println("helloWorld"); + const char text[] = "Hello World!"; + // most e-papers have width < height (portrait) as native orientation, especially the small ones + // in GxEPD2 rotation 0 is used for native orientation (most TFT libraries use 0 fix for portrait orientation) + // set rotation to 1 (rotate right 90 degrees) to have enough space on small diplay2s (landscape) + diplay2.setRotation(1); + // select a suitable font in Adafruit_GFX + diplay2.setFont(&FreeMonoBold9pt7b); + // on e-papers black on white is more pleasant to read + diplay2.setTextColor(GxEPD_BLACK); + // Adafruit_GFX has a handy method getTextBounds() to determine the boundary box for a text for the actual font + int16_t tbx, tby; + uint16_t tbw, tbh; // boundary box window + diplay2.getTextBounds(text, 0, 0, &tbx, &tby, &tbw, &tbh); // it works for origin 0, 0, fortunately (negative tby!) + // center bounding box by transposition of origin: + uint16_t x = ((diplay2.width() - tbw) / 2) - tbx; + uint16_t y = ((diplay2.height() - tbh) / 2) - tby; + // full window mode is the initial mode, set it anyway + diplay2.setFullWindow(); + // here we use paged drawing, even if the processor has enough RAM for full buffer + // so this can be used with any supported processor board. + // the cost in code overhead and execution time penalty is marginal + // tell the graphics class to use paged drawing mode + diplay2.firstPage(); + do + { + // this part of code is executed multiple times, as many as needed, + // in case of full buffer it is executed once + // IMPORTANT: each iteration needs to draw the same, to avoid strange effects + // use a copy of values that might change, don't read e.g. from analog or pins in the loop! + diplay2.fillScreen(GxEPD_WHITE); // set the background to white (fill the buffer with value for white) + diplay2.setCursor(x, y); // set the postition to start printing text + diplay2.print(text); // print some text + // end of part executed multiple times + } + // tell the graphics class to transfer the buffer content (page) to the controller buffer + // the graphics class will command the controller to refresh to the screen when the last page has been transferred + // returns true if more pages need be drawn and transferred + // returns false if the last page has been transferred and the screen refreshed for panels without fast partial update + // returns false for panels with fast partial update when the controller buffer has been written once more, to make the differential buffers equal + // (for full buffered with fast partial update the (full) buffer is just transferred again, and false returned) + while (diplay2.nextPage()); + //Serial.println("helloWorld done"); +} + +void helloFullScreenPartialMode() +{ + //Serial.println("helloFullScreenPartialMode"); + const char fullscreen[] = "full screen update"; + const char fpm[] = "fast partial mode"; + const char spm[] = "slow partial mode"; + const char npm[] = "no partial mode"; + diplay2.setPartialWindow(0, 0, diplay2.width(), diplay2.height()); + diplay2.setRotation(1); + diplay2.setFont(&FreeMonoBold9pt7b); + diplay2.setTextColor(GxEPD_BLACK); + const char *updatemode; + if (diplay2.epd2.hasFastPartialUpdate) + { + updatemode = fpm; + } + else if (diplay2.epd2.hasPartialUpdate) + { + updatemode = spm; + } + else + { + updatemode = npm; + } + // do this outside of the loop + int16_t tbx, tby; + uint16_t tbw, tbh; + // center update text + diplay2.getTextBounds(fullscreen, 0, 0, &tbx, &tby, &tbw, &tbh); + uint16_t utx = ((diplay2.width() - tbw) / 2) - tbx; + uint16_t uty = ((diplay2.height() / 4) - tbh / 2) - tby; + // center update mode + diplay2.getTextBounds(updatemode, 0, 0, &tbx, &tby, &tbw, &tbh); + uint16_t umx = ((diplay2.width() - tbw) / 2) - tbx; + uint16_t umy = ((diplay2.height() * 3 / 4) - tbh / 2) - tby; + // center HelloWorld + diplay2.getTextBounds(HelloWorld, 0, 0, &tbx, &tby, &tbw, &tbh); + uint16_t hwx = ((diplay2.width() - tbw) / 2) - tbx; + uint16_t hwy = ((diplay2.height() - tbh) / 2) - tby; + diplay2.firstPage(); + do + { + diplay2.fillScreen(GxEPD_WHITE); + diplay2.setCursor(hwx, hwy); + diplay2.print(HelloWorld); + diplay2.setCursor(utx, uty); + diplay2.print(fullscreen); + diplay2.setCursor(umx, umy); + diplay2.print(updatemode); + } while (diplay2.nextPage()); + //Serial.println("helloFullScreenPartialMode done"); +} + +void helloArduino() +{ + //Serial.println("helloArduino"); + diplay2.setRotation(1); + diplay2.setFont(&FreeMonoBold9pt7b); + diplay2.setTextColor(diplay2.epd2.hasColor ? GxEPD_RED : GxEPD_BLACK); + int16_t tbx, tby; + uint16_t tbw, tbh; + // align with centered HelloWorld + diplay2.getTextBounds(HelloWorld, 0, 0, &tbx, &tby, &tbw, &tbh); + uint16_t x = ((diplay2.width() - tbw) / 2) - tbx; + // height might be different + diplay2.getTextBounds(HelloArduino, 0, 0, &tbx, &tby, &tbw, &tbh); + uint16_t y = ((diplay2.height() / 4) - tbh / 2) - tby; // y is base line! + // make the window big enough to cover (overwrite) descenders of previous text + uint16_t wh = FreeMonoBold9pt7b.yAdvance; + uint16_t wy = (diplay2.height() / 4) - wh / 2; + diplay2.setPartialWindow(0, wy, diplay2.width(), wh); + diplay2.firstPage(); + do + { + diplay2.fillScreen(GxEPD_WHITE); + //diplay2.drawRect(x, y - tbh, tbw, tbh, GxEPD_BLACK); + diplay2.setCursor(x, y); + diplay2.print(HelloArduino); + } while (diplay2.nextPage()); + delay(1000); + //Serial.println("helloArduino done"); +} + +void helloEpaper() +{ + //Serial.println("helloEpaper"); + diplay2.setRotation(1); + diplay2.setFont(&FreeMonoBold9pt7b); + diplay2.setTextColor(diplay2.epd2.hasColor ? GxEPD_RED : GxEPD_BLACK); + int16_t tbx, tby; + uint16_t tbw, tbh; + // align with centered HelloWorld + diplay2.getTextBounds(HelloWorld, 0, 0, &tbx, &tby, &tbw, &tbh); + uint16_t x = ((diplay2.width() - tbw) / 2) - tbx; + // height might be different + diplay2.getTextBounds(HelloEpaper, 0, 0, &tbx, &tby, &tbw, &tbh); + uint16_t y = (diplay2.height() * 3 / 4) + tbh / 2; // y is base line! + // make the window big enough to cover (overwrite) descenders of previous text + uint16_t wh = FreeMonoBold9pt7b.yAdvance; + uint16_t wy = (diplay2.height() * 3 / 4) - wh / 2; + diplay2.setPartialWindow(0, wy, diplay2.width(), wh); + diplay2.firstPage(); + do + { + diplay2.fillScreen(GxEPD_WHITE); + diplay2.setCursor(x, y); + diplay2.print(HelloEpaper); + } while (diplay2.nextPage()); + //Serial.println("helloEpaper done"); +} + +#if defined(ESP8266) || defined(ESP32) +#include +#define PrintString StreamString +#else +class PrintString : public Print, public String +{ +public: + size_t write(uint8_t data) override + { + return concat(char(data)); + }; +}; +#endif + +void helloValue(double v, int digits) +{ + //Serial.println("helloValue"); + diplay2.setRotation(1); + diplay2.setFont(&FreeMonoBold9pt7b); + diplay2.setTextColor(diplay2.epd2.hasColor ? GxEPD_RED : GxEPD_BLACK); + PrintString valueString; + valueString.print(v, digits); + int16_t tbx, tby; + uint16_t tbw, tbh; + diplay2.getTextBounds(valueString, 0, 0, &tbx, &tby, &tbw, &tbh); + uint16_t x = ((diplay2.width() - tbw) / 2) - tbx; + uint16_t y = (diplay2.height() * 3 / 4) + tbh / 2; // y is base line! + // show what happens, if we use the bounding box for partial window + uint16_t wx = (diplay2.width() - tbw) / 2; + uint16_t wy = (diplay2.height() * 3 / 4) - tbh / 2; + diplay2.setPartialWindow(wx, wy, tbw, tbh); + diplay2.firstPage(); + do + { + diplay2.fillScreen(GxEPD_WHITE); + diplay2.setCursor(x, y); + diplay2.print(valueString); + } while (diplay2.nextPage()); + delay(2000); + // make the partial window big enough to cover the previous text + uint16_t ww = tbw; // remember window width + diplay2.getTextBounds(HelloEpaper, 0, 0, &tbx, &tby, &tbw, &tbh); + // adjust, because HelloEpaper was aligned, not centered (could calculate this to be precise) + ww = max(ww, uint16_t(tbw + 12)); // 12 seems ok + wx = (diplay2.width() - tbw) / 2; + // make the window big enough to cover (overwrite) descenders of previous text + uint16_t wh = FreeMonoBold9pt7b.yAdvance; + wy = (diplay2.height() * 3 / 4) - wh / 2; + diplay2.setPartialWindow(wx, wy, ww, wh); + // alternately use the whole width for partial window + //diplay2.setPartialWindow(0, wy, diplay2.width(), wh); + diplay2.firstPage(); + do + { + diplay2.fillScreen(GxEPD_WHITE); + diplay2.setCursor(x, y); + diplay2.print(valueString); + } while (diplay2.nextPage()); + //Serial.println("helloValue done"); +} + +void deepSleepTest() +{ + //Serial.println("deepSleepTest"); + const char hibernating[] = "hibernating ..."; + const char wokeup[] = "woke up"; + const char from[] = "from deep sleep"; + const char again[] = "again"; + diplay2.setRotation(1); + diplay2.setFont(&FreeMonoBold9pt7b); + diplay2.setTextColor(GxEPD_BLACK); + int16_t tbx, tby; + uint16_t tbw, tbh; + // center text + diplay2.getTextBounds(hibernating, 0, 0, &tbx, &tby, &tbw, &tbh); + uint16_t x = ((diplay2.width() - tbw) / 2) - tbx; + uint16_t y = ((diplay2.height() - tbh) / 2) - tby; + diplay2.setFullWindow(); + diplay2.firstPage(); + do + { + diplay2.fillScreen(GxEPD_WHITE); + diplay2.setCursor(x, y); + diplay2.print(hibernating); + } while (diplay2.nextPage()); + diplay2.hibernate(); + delay(5000); + diplay2.getTextBounds(wokeup, 0, 0, &tbx, &tby, &tbw, &tbh); + uint16_t wx = (diplay2.width() - tbw) / 2; + uint16_t wy = (diplay2.height() / 3) + tbh / 2; // y is base line! + diplay2.getTextBounds(from, 0, 0, &tbx, &tby, &tbw, &tbh); + uint16_t fx = (diplay2.width() - tbw) / 2; + uint16_t fy = (diplay2.height() * 2 / 3) + tbh / 2; // y is base line! + diplay2.firstPage(); + do + { + diplay2.fillScreen(GxEPD_WHITE); + diplay2.setCursor(wx, wy); + diplay2.print(wokeup); + diplay2.setCursor(fx, fy); + diplay2.print(from); + } while (diplay2.nextPage()); + delay(5000); + diplay2.getTextBounds(hibernating, 0, 0, &tbx, &tby, &tbw, &tbh); + uint16_t hx = (diplay2.width() - tbw) / 2; + uint16_t hy = (diplay2.height() / 3) + tbh / 2; // y is base line! + diplay2.getTextBounds(again, 0, 0, &tbx, &tby, &tbw, &tbh); + uint16_t ax = (diplay2.width() - tbw) / 2; + uint16_t ay = (diplay2.height() * 2 / 3) + tbh / 2; // y is base line! + diplay2.firstPage(); + do + { + diplay2.fillScreen(GxEPD_WHITE); + diplay2.setCursor(hx, hy); + diplay2.print(hibernating); + diplay2.setCursor(ax, ay); + diplay2.print(again); + } while (diplay2.nextPage()); + diplay2.hibernate(); + //Serial.println("deepSleepTest done"); +} + +void showBox(uint16_t x, uint16_t y, uint16_t w, uint16_t h, bool partial) +{ + //Serial.println("showBox"); + diplay2.setRotation(1); + if (partial) + { + diplay2.setPartialWindow(x, y, w, h); + } + else + { + diplay2.setFullWindow(); + } + diplay2.firstPage(); + do + { + diplay2.fillScreen(GxEPD_WHITE); + diplay2.fillRect(x, y, w, h, GxEPD_BLACK); + } while (diplay2.nextPage()); + //Serial.println("showBox done"); +} + +void drawCornerTest() +{ + diplay2.setFullWindow(); + diplay2.setFont(&FreeMonoBold9pt7b); + diplay2.setTextColor(GxEPD_BLACK); + for (uint16_t r = 0; r <= 4; r++) + { + diplay2.setRotation(r); + diplay2.firstPage(); + do + { + diplay2.fillScreen(GxEPD_WHITE); + diplay2.fillRect(0, 0, 8, 8, GxEPD_BLACK); + diplay2.fillRect(diplay2.width() - 18, 0, 16, 16, GxEPD_BLACK); + diplay2.fillRect(diplay2.width() - 25, diplay2.height() - 25, 24, 24, GxEPD_BLACK); + diplay2.fillRect(0, diplay2.height() - 33, 32, 32, GxEPD_BLACK); + diplay2.setCursor(diplay2.width() / 2, diplay2.height() / 2); + diplay2.print(diplay2.getRotation()); + } while (diplay2.nextPage()); + delay(2000); + } +} + +void showFont(const char name[], const GFXfont *f) +{ + diplay2.setFullWindow(); + diplay2.setRotation(0); + diplay2.setTextColor(GxEPD_BLACK); + diplay2.firstPage(); + do + { + drawFont(name, f); + } while (diplay2.nextPage()); +} + +void drawFont(const char name[], const GFXfont *f) +{ + //diplay2.setRotation(0); + diplay2.fillScreen(GxEPD_WHITE); + diplay2.setTextColor(GxEPD_BLACK); + diplay2.setFont(f); + diplay2.setCursor(0, 0); + diplay2.println(); + diplay2.println(name); + diplay2.println(" !\"#$%&'()*+,-./"); + diplay2.println("0123456789:;<=>?"); + diplay2.println("@ABCDEFGHIJKLMNO"); + diplay2.println("PQRSTUVWXYZ[\\]^_"); + if (diplay2.epd2.hasColor) + { + diplay2.setTextColor(GxEPD_RED); + } + diplay2.println("`abcdefghijklmno"); + diplay2.println("pqrstuvwxyz{|}~ "); +} + +// note for partial update window and setPartialWindow() method: +// partial update window size and position is on byte boundary in physical x direction +// the size is increased in setPartialWindow() if x or w are not multiple of 8 for even rotation, y or h for odd rotation +// see also comment in GxEPD2_BW.h, GxEPD2_3C.h or GxEPD2_GFX.h for method setPartialWindow() +// showPartialUpdate() purposely uses values that are not multiples of 8 to test this + +void showPartialUpdate() +{ + // some useful background + helloWorld(); + // use asymmetric values for test + uint16_t box_x = 10; + uint16_t box_y = 15; + uint16_t box_w = 70; + uint16_t box_h = 20; + uint16_t cursor_y = box_y + box_h - 6; + float value = 13.95; + uint16_t incr = diplay2.epd2.hasFastPartialUpdate ? 1 : 3; + diplay2.setFont(&FreeMonoBold9pt7b); + diplay2.setTextColor(GxEPD_BLACK); + // show where the update box is + for (uint16_t r = 0; r < 4; r++) + { + diplay2.setRotation(r); + diplay2.setPartialWindow(box_x, box_y, box_w, box_h); + diplay2.firstPage(); + do + { + diplay2.fillRect(box_x, box_y, box_w, box_h, GxEPD_BLACK); + //diplay2.fillScreen(GxEPD_BLACK); + } while (diplay2.nextPage()); + delay(2000); + diplay2.firstPage(); + do + { + diplay2.fillRect(box_x, box_y, box_w, box_h, GxEPD_WHITE); + } while (diplay2.nextPage()); + delay(1000); + } + //return; + // show updates in the update box + for (uint16_t r = 0; r < 4; r++) + { + diplay2.setRotation(r); + diplay2.setPartialWindow(box_x, box_y, box_w, box_h); + for (uint16_t i = 1; i <= 10; i += incr) + { + diplay2.firstPage(); + do + { + diplay2.fillRect(box_x, box_y, box_w, box_h, GxEPD_WHITE); + diplay2.setCursor(box_x, cursor_y); + diplay2.print(value * i, 2); + } while (diplay2.nextPage()); + delay(500); + } + delay(1000); + diplay2.firstPage(); + do + { + diplay2.fillRect(box_x, box_y, box_w, box_h, GxEPD_WHITE); + } while (diplay2.nextPage()); + delay(1000); + } +} + +void drawBitmaps() +{ + diplay2.setFullWindow(); + + drawBitmaps640x384(); +} + +void drawBitmaps640x384() +{ + const unsigned char *bitmaps[] = + { + Bitmap640x384_1, Bitmap640x384_2}; + + if ((diplay2.epd2.panel == GxEPD2::GDEW075T8) || (diplay2.epd2.panel == GxEPD2::GDEW075Z09)) + { + for (uint16_t i = 0; i < sizeof(bitmaps) / sizeof(char *); i++) + { + diplay2.firstPage(); + do + { + diplay2.fillScreen(GxEPD_WHITE); + diplay2.drawInvertedBitmap(0, 0, bitmaps[i], diplay2.epd2.WIDTH, diplay2.epd2.HEIGHT, GxEPD_BLACK); + } while (diplay2.nextPage()); + delay(2000); + } + } +} diff --git a/src/main.cpp b/src/main.cpp index 1e55e37..c3261c7 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,14 +1,14 @@ #include #include +#include "device.h" #include "wlan.h" #include "display.h" #include "cloud.h" -// TODO client settings -//#define config_PullServer "http://smart-sign-server/satellite/get-data" // pull server address -//RTC_DATA_ATTR long config_DeepSleepInterval = 300; // 5 min pull intervall -//String config_UUID = ""; -// TODO client settings + +void gotoDeepSleep(); +String getWakeupReason(); + void setup() { @@ -17,19 +17,26 @@ void setup() Serial.begin(115200); delay(100); //Take some time to open up the Serial Monitor Serial.println(); + Serial.println("setup..."); + Serial.println(); + setupDisplay(); // setup hardware //setupConfig(); //setupDeepSleep(); + setupDevice(); setupWlan(); setupCloud(); - // SPIFFS.begin(true); // formatOnFail - - Serial.println("setup done"); + Serial.println(); + Serial.println("setup... done"); } void loop() { // put your main code here, to run repeatedly: + + loopCloud(); + loopDevice(); + } \ No newline at end of file diff --git a/src/wlan.cpp b/src/wlan.cpp index daefaa5..2c66e5e 100644 --- a/src/wlan.cpp +++ b/src/wlan.cpp @@ -2,35 +2,51 @@ #include #include "wlan.h" -const char* ssid = ""; -const char* password = ""; - +const char *ssid = ""; +const char *password = ""; void setupWlan() { - - Serial.println("setup Wlan"); - long startMills = millis(); - - WiFi.mode(WIFI_STA); - WiFi.setHostname("smart-sign"); - WiFi.begin(ssid, password); - Serial.println(millis() - startMills); - - //WiFi.config(IPAddress(192, 168, 178, 62), IPAddress(192, 168, 178, 1), IPAddress(192, 168, 178, 1), IPAddress(255, 255, 255, 0)); - Serial.println(millis() - startMills); - - while (WiFi.waitForConnectResult() != WL_CONNECTED) { - Serial.println("Connection Failed! Rebooting..."); - delay(100); - ESP.restart(); - } - Serial.println(millis() - startMills); - + Serial.println("setup Wlan"); + long startMills = millis(); + + WiFi.mode(WIFI_STA); + WiFi.setHostname("paperdash-display"); + + Serial.print("Connecting to "); + Serial.println(ssid); + + WiFi.begin(ssid, password); + Serial.println(millis() - startMills); + +/* + while (WiFi.status() != WL_CONNECTED) { + delay(100); + Serial.print("."); + } + */ + + //WiFi.config(IPAddress(192, 168, 178, 62), IPAddress(192, 168, 178, 1), IPAddress(192, 168, 178, 1), IPAddress(255, 255, 255, 0)); + //Serial.println(millis() - startMills); + + while (WiFi.waitForConnectResult() != WL_CONNECTED) + { + Serial.println("Connection Failed! Rebooting..."); + delay(100); + ESP.restart(); + } + + Serial.println(""); + Serial.println("WiFi connected"); + Serial.println("IP address: "); + Serial.println(WiFi.localIP()); + + Serial.print("connected in: "); + Serial.println(millis() - startMills); } void disableWlan() { - Serial.println("disable Wlan"); - //esp_wifi_stop(); + Serial.println("disable Wlan"); + //esp_wifi_stop(); } \ No newline at end of file