diff --git a/examples/Wifi_Image/README.md b/examples/Wifi_Image/README.md new file mode 100644 index 0000000..1d45d9b --- /dev/null +++ b/examples/Wifi_Image/README.md @@ -0,0 +1,6 @@ +# Hello World +This example displays "Hello World" in the middle of the screen and is intended as a super simple, minimal example to show how to display text on the screen. + +## Usage + +Install the Paperd.ink library as explained in the [documentation](https://docs.paperd.ink). Change the `PAPERDINK_DEVICE` on the first line in the example if you have a Merlot Paperd.ink, leave it as is when you have a Classic one. Compile and upload this example to the Paperd.ink device. If everything is successful, the text "Hello World" is displayed in white on a black background. diff --git a/examples/Wifi_Image/Wifi_Image.ino b/examples/Wifi_Image/Wifi_Image.ino new file mode 100644 index 0000000..e669b2f --- /dev/null +++ b/examples/Wifi_Image/Wifi_Image.ino @@ -0,0 +1,67 @@ +/* The MIT License (MIT) + * Copyright (c) 2022 Paperd.Ink + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* config.h should be before Paperdink.h */ +#include "config.h" +#include + +/* Create paperdink object */ +PAPERDINK_DEVICE Paperdink; + +void setup() +{ + /* Comment this line to disable Serial debug output */ + DEBUG.begin(115200); + + /* Initialize device */ + Paperdink.begin(); + /* Enable power to display */ + Paperdink.enable_display(); + /* Clear the background */ + Paperdink.epd.fillScreen(GxEPD_WHITE); + /* Connect to Wifi */ + if (Paperdink.connect_wifi(WIFI_NAME, PASSWORD) < 0) { + DEBUG.println("Unable to connect to WiFi"); + Paperdink.epd.drawBitmap(370, 4, wifi_off_sml, wifi_off_sml_width, wifi_off_sml_height, GxEPD_BLACK); + } else { + Paperdink_UI.display_bitmap_https(Paperdink.epd, HOST, PORT, PATH, IMG_FILE, 0, 0, false); + + /* Send data to display for the update */ + Paperdink.epd.display(); + } + + DEBUG.println("Turning off everything"); + + /* Sleep till update time. + * Align updates to 12am so that date change aligns + * with actual day change. + */ + uint64_t sleep_time = (86400 / (UPDATES_PER_DAY)) - (((Paperdink_Date.mil_hour * 3600) + (Paperdink_Date.min * 60) + (Paperdink_Date.sec)) % (86400 / UPDATES_PER_DAY)); + + /* Update after sleep_time microsecond or when button 1 is pressed. */ + // Paperdink.deep_sleep_timer_wakeup(sleep_time*S_TO_uS_FACTOR); // Consumes lower current + Paperdink.deep_sleep_timer_button_wakeup(sleep_time * S_TO_uS_FACTOR, BUTTON_1_PIN); // Consumes higher current +} + +void loop() +{ +} + diff --git a/examples/Wifi_Image/Wifi_Image.orig b/examples/Wifi_Image/Wifi_Image.orig new file mode 100644 index 0000000..15c2bc6 --- /dev/null +++ b/examples/Wifi_Image/Wifi_Image.orig @@ -0,0 +1,67 @@ +/* The MIT License (MIT) + * Copyright (c) 2022 Paperd.Ink + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* config.h should be before Paperdink.h */ +#include "config.h" +#include + +/* Create paperdink object */ +PAPERDINK_DEVICE Paperdink; + +void setup() +{ + /* Comment this line to disable Serial debug output */ + DEBUG.begin(115200); + + /* Initialize device */ + Paperdink.begin(); + /* Enable power to display */ + Paperdink.enable_display(); + /* Clear the background */ + Paperdink.epd.fillScreen(GxEPD_WHITE); + /* Connect to Wifi */ + if (Paperdink.connect_wifi(WIFI_NAME, PASSWORD) < 0) { + DEBUG.println("Unable to connect to WiFi"); + Paperdink.epd.drawBitmap(370, 4, wifi_off_sml, wifi_off_sml_width, wifi_off_sml_height, GxEPD_BLACK); + } else { + Paperdink_UI.display_bitmap_https(Paperdink.epd, HOST, PATH, IMG_FILE, 0, 0, false); + + /* Send data to display for the update */ + Paperdink.epd.display(); + } + + DEBUG.println("Turning off everything"); + + /* Sleep till update time. + * Align updates to 12am so that date change aligns + * with actual day change. + */ + uint64_t sleep_time = (86400 / (UPDATES_PER_DAY)) - (((Paperdink_Date.mil_hour * 3600) + (Paperdink_Date.min * 60) + (Paperdink_Date.sec)) % (86400 / UPDATES_PER_DAY)); + + /* Update after sleep_time microsecond or when button 1 is pressed. */ + // Paperdink.deep_sleep_timer_wakeup(sleep_time*S_TO_uS_FACTOR); // Consumes lower current + Paperdink.deep_sleep_timer_button_wakeup(sleep_time * S_TO_uS_FACTOR, BUTTON_1_PIN); // Consumes higher current +} + +void loop() +{ +} + diff --git a/examples/Wifi_Image/config.h b/examples/Wifi_Image/config.h new file mode 100644 index 0000000..1aa0876 --- /dev/null +++ b/examples/Wifi_Image/config.h @@ -0,0 +1,32 @@ +#ifndef CONFIG_H +#define CONFIG_H + +/* CONFIGURATION + * Uncomment only one of the below #define statements + * based on the paperd.ink device you have + */ +#define PAPERDINK_DEVICE Paperdink_Classic +//#define PAPERDINK_DEVICE Paperdink_Merlot + +#define WIFI_NAME "HalfBloodKumar" // Wifi Network SSID (name of wifi network) +#define PASSWORD "Summer@2022" // Wifi Network password + +/* Time zone from list https://github.com/nayarsystems/posix_tz_db/blob/master/zones.csv */ +#define TIME_ZONE "PST8PDT,M3.2.0,M11.1.0" + +/* Number of times to update starting 12am + * 1 = Updates every 24 hours + * 2 = Updates every 12 hours + * 3 = Updates every 8 hours. Not a good idea since it won't align with day changes. + * 4 = Updates every 6 hours + * ... and so on + * Higher number means lower battery life + */ +#define UPDATES_PER_DAY 4 + +/* Image URL configuration */ +#define HOST "192.168.1.144" +#define PORT 8010 +#define PATH "/" +#define IMG_FILE "image.bmp" +#endif /* CONFIG_H */ diff --git a/src/paperdink_common.h b/src/paperdink_common.h index 717444b..2c28df0 100644 --- a/src/paperdink_common.h +++ b/src/paperdink_common.h @@ -10,6 +10,8 @@ #include #include #include +#include +#include #include "fonts.h" #include "icons.h" diff --git a/src/ui/ui_base.cpp b/src/ui/ui_base.cpp index 59a50da..bd71963 100644 --- a/src/ui/ui_base.cpp +++ b/src/ui/ui_base.cpp @@ -44,6 +44,7 @@ static const uint16_t max_palette_pixels = 256; // for depth <= static uint8_t input_buffer[3 * input_buffer_pixels]; // up to depth 24 static uint8_t mono_palette_buffer[max_palette_pixels / 8]; // palette buffer for depth <= 8 b/w static uint8_t color_palette_buffer[max_palette_pixels / 8]; // palette buffer for depth <= 8 c/w +uint16_t rgb_palette_buffer[max_palette_pixels]; // palette buffer for depth <= 8 for buffered graphics, needed for 7-color display uint16_t PaperdinkUIClass::read16(File& f) { @@ -55,6 +56,15 @@ uint16_t PaperdinkUIClass::read16(File& f) return result; } +uint16_t PaperdinkUIClass::read16(WiFiClient& client) +{ + // BMP data is stored little-endian, same as Arduino. + uint16_t result; + ((uint8_t *)&result)[0] = client.read(); // LSB + ((uint8_t *)&result)[1] = client.read(); // MSB + return result; +} + uint32_t PaperdinkUIClass::read32(File& f) { // BMP data is stored little-endian, same as Arduino. @@ -67,6 +77,52 @@ uint32_t PaperdinkUIClass::read32(File& f) return result; } +uint32_t PaperdinkUIClass::read32(WiFiClient& client) +{ + // BMP data is stored little-endian, same as Arduino. + uint32_t result; + ((uint8_t *)&result)[0] = client.read(); // LSB + ((uint8_t *)&result)[1] = client.read(); + ((uint8_t *)&result)[2] = client.read(); + ((uint8_t *)&result)[3] = client.read(); // MSB + return result; +} + +uint32_t PaperdinkUIClass::skip(WiFiClient& client, int32_t bytes) +{ + int32_t remain = bytes; + uint32_t start = millis(); + while ((client.connected() || client.available()) && (remain > 0)) + { + if (client.available()) + { + int16_t v = client.read(); + remain--; + } + else delay(1); + if (millis() - start > 2000) break; // don't hang forever + } + return bytes - remain; +} + +uint32_t PaperdinkUIClass::read8n(WiFiClient& client, uint8_t* buffer, int32_t bytes) +{ + int32_t remain = bytes; + uint32_t start = millis(); + while ((client.connected() || client.available()) && (remain > 0)) + { + if (client.available()) + { + int16_t v = client.read(); + *buffer++ = uint8_t(v); + remain--; + } + else delay(1); + if (millis() - start > 2000) break; // don't hang forever + } + return bytes - remain; +} + void PaperdinkUIClass::display_bitmap_fs(GxEPD2_GFX& display, fs::FS &fs, const char *filename, int16_t x, int16_t y, bool with_color) { File file; @@ -151,52 +207,52 @@ void PaperdinkUIClass::display_bitmap_fs(GxEPD2_GFX& display, fs::FS &fs, const uint16_t color = GxEPD_BLACK; file.seekSet(rowPosition); for (uint16_t col = 0; col < w; col++) { // for each pixel - // Time to read more pixel data? + // Time to read more pixel data? if (in_idx >= in_bytes) { // ok, exact match for 24bit also (size IS multiple of 3) in_bytes = file.read(input_buffer, in_remain > sizeof(input_buffer) ? sizeof(input_buffer) : in_remain); in_remain -= in_bytes; in_idx = 0; } switch (depth) { - case 24: - blue = input_buffer[in_idx++]; - green = input_buffer[in_idx++]; - red = input_buffer[in_idx++]; - whitish = with_color ? ((red > 0x80) && (green > 0x80) && (blue > 0x80)) : ((red + green + blue) > 3 * 0x80); // whitish - colored = (red > 0xF0) || ((green > 0xF0) && (blue > 0xF0)); // reddish or yellowish? - break; - case 16: - { - uint8_t lsb = input_buffer[in_idx++]; - uint8_t msb = input_buffer[in_idx++]; - if (format == 0) { // 555 - blue = (lsb & 0x1F) << 3; - green = ((msb & 0x03) << 6) | ((lsb & 0xE0) >> 2); - red = (msb & 0x7C) << 1; - } else {// 565 - blue = (lsb & 0x1F) << 3; - green = ((msb & 0x07) << 5) | ((lsb & 0xE0) >> 3); - red = (msb & 0xF8); - } - whitish = with_color ? ((red > 0x80) && (green > 0x80) && (blue > 0x80)) : ((red + green + blue) > 3 * 0x80); // whitish - colored = (red > 0xF0) || ((green > 0xF0) && (blue > 0xF0)); // reddish or yellowish? - } - break; - case 1: - case 4: - case 8: - { - if (0 == in_bits) { - in_byte = input_buffer[in_idx++]; - in_bits = 8; - } - uint16_t pn = (in_byte >> bitshift) & bitmask; - whitish = mono_palette_buffer[pn / 8] & (0x1 << pn % 8); - colored = color_palette_buffer[pn / 8] & (0x1 << pn % 8); - in_byte <<= depth; - in_bits -= depth; - } - break; + case 24: + blue = input_buffer[in_idx++]; + green = input_buffer[in_idx++]; + red = input_buffer[in_idx++]; + whitish = with_color ? ((red > 0x80) && (green > 0x80) && (blue > 0x80)) : ((red + green + blue) > 3 * 0x80); // whitish + colored = (red > 0xF0) || ((green > 0xF0) && (blue > 0xF0)); // reddish or yellowish? + break; + case 16: + { + uint8_t lsb = input_buffer[in_idx++]; + uint8_t msb = input_buffer[in_idx++]; + if (format == 0) { // 555 + blue = (lsb & 0x1F) << 3; + green = ((msb & 0x03) << 6) | ((lsb & 0xE0) >> 2); + red = (msb & 0x7C) << 1; + } else {// 565 + blue = (lsb & 0x1F) << 3; + green = ((msb & 0x07) << 5) | ((lsb & 0xE0) >> 3); + red = (msb & 0xF8); + } + whitish = with_color ? ((red > 0x80) && (green > 0x80) && (blue > 0x80)) : ((red + green + blue) > 3 * 0x80); // whitish + colored = (red > 0xF0) || ((green > 0xF0) && (blue > 0xF0)); // reddish or yellowish? + } + break; + case 1: + case 4: + case 8: + { + if (0 == in_bits) { + in_byte = input_buffer[in_idx++]; + in_bits = 8; + } + uint16_t pn = (in_byte >> bitshift) & bitmask; + whitish = mono_palette_buffer[pn / 8] & (0x1 << pn % 8); + colored = color_palette_buffer[pn / 8] & (0x1 << pn % 8); + in_byte <<= depth; + in_bits -= depth; + } + break; } if (whitish) color = GxEPD_WHITE; @@ -216,4 +272,255 @@ void PaperdinkUIClass::display_bitmap_fs(GxEPD2_GFX& display, fs::FS &fs, const DEBUG.println("bitmap format not handled."); } +void PaperdinkUIClass::display_bitmap_https(GxEPD2_GFX& display, const char* host, const int httpsPort, const char* path, const char* filename, int16_t x, int16_t y, bool with_color, const char* certificate) +{ + // Use WiFiClientSecure class to create TLS connection +#if USE_BearSSL + BearSSL::WiFiClientSecure client; +#else + //WiFiClientSecure client; + WiFiClient client; +#endif + + bool connection_ok = false; + bool valid = false; // valid format to be handled + bool flip = true; // bitmap is stored bottom-to-top + bool has_multicolors = display.epd2.panel == GxEPD2::ACeP565; + uint32_t startTime = millis(); + if ((x >= display.width()) || (y >= display.height())) return; + Serial.printf("connecting to %s:%d\r\n",host, httpsPort); + + //if (certificate) client.setCACert(certificate); + + if (!client.connect(host, httpsPort)) + { + Serial.println("connection failed"); + return; + } + Serial.print("requesting URL: "); + Serial.println(String("https://") + host + path + filename); + client.print(String("GET ") + path + filename + " HTTP/1.0\r\n" + + "Host: " + host + "\r\n" + + "User-Agent: Paperd.Ink\r\n" + + "Connection: close\r\n\r\n"); + Serial.println("request sent"); + while (client.connected()) + { + String line = client.readStringUntil('\n'); + if (!connection_ok) + { + connection_ok = line.startsWith("HTTP/1.0 200 OK"); + if (connection_ok) Serial.println(line); + //if (!connection_ok) Serial.println(line); + } + if (!connection_ok) Serial.println(line); + //Serial.println(line); + if (line == "\r") + { + Serial.println("headers received"); + break; + } + } + if (!connection_ok){ + Serial.println("connection not ok"); + return; + } + // Parse BMP header + uint16_t signature = 0; + for (int16_t i = 0; i < 50; i++) + { + if (!client.available()) delay(100); + else signature = read16(client); + if (signature == 0x4D42) + { + //Serial.print("signature wait loops: "); Serial.println(i); + break; + } + } + + if (signature == 0x4D42) // BMP signature + { + uint32_t fileSize = read32(client); + uint32_t creatorBytes = read32(client); + uint32_t imageOffset = read32(client); // Start of image data + uint32_t headerSize = read32(client); + uint32_t width = read32(client); + uint32_t height = read32(client); + uint16_t planes = read16(client); + uint16_t depth = read16(client); // bits per pixel + uint32_t format = read32(client); + uint32_t bytes_read = 7 * 4 + 3 * 2; // read so far + if ((planes == 1) && ((format == 0) || (format == 3))) // uncompressed is handled, 565 also + { + Serial.print("File size: "); Serial.println(fileSize); + Serial.print("Image Offset: "); Serial.println(imageOffset); + Serial.print("Header size: "); Serial.println(headerSize); + Serial.print("Bit Depth: "); Serial.println(depth); + Serial.print("Image size: "); + Serial.print(width); + Serial.print('x'); + Serial.println(height); + // BMP rows are padded (if needed) to 4-byte boundary + uint32_t rowSize = (width * depth / 8 + 3) & ~3; + if (depth < 8) rowSize = ((width * depth + 8 - depth) / 8 + 3) & ~3; + if (height < 0) + { + height = -height; + flip = false; + } + uint16_t w = width; + uint16_t h = height; + if ((x + w - 1) >= display.width()) w = display.width() - x; + if ((y + h - 1) >= display.height()) h = display.height() - y; + //if (w <= max_row_width) // handle with direct drawing + { + valid = true; + uint8_t bitmask = 0xFF; + uint8_t bitshift = 8 - depth; + uint16_t red, green, blue; + bool whitish, colored; + if (depth == 1) with_color = false; + if (depth <= 8) + { + if (depth < 8) bitmask >>= depth; + //bytes_read += skip(client, 54 - bytes_read); //palette is always @ 54 + bytes_read += skip(client, imageOffset - (4 << depth) - bytes_read); // 54 for regular, diff for colorsimportant + for (uint16_t pn = 0; pn < (1 << depth); pn++) + { + blue = client.read(); + green = client.read(); + red = client.read(); + client.read(); + bytes_read += 4; + whitish = with_color ? ((red > 0x80) && (green > 0x80) && (blue > 0x80)) : ((red + green + blue) > 3 * 0x80); // whitish + colored = (red > 0xF0) || ((green > 0xF0) && (blue > 0xF0)); // reddish or yellowish? + if (0 == pn % 8) mono_palette_buffer[pn / 8] = 0; + mono_palette_buffer[pn / 8] |= whitish << pn % 8; + if (0 == pn % 8) color_palette_buffer[pn / 8] = 0; + color_palette_buffer[pn / 8] |= colored << pn % 8; + //Serial.print("0x00"); Serial.print(red, HEX); Serial.print(green, HEX); Serial.print(blue, HEX); + //Serial.print(" : "); Serial.print(whitish); Serial.print(", "); Serial.println(colored); + rgb_palette_buffer[pn] = ((red & 0xF8) << 8) | ((green & 0xFC) << 3) | ((blue & 0xF8) >> 3); + } + } + uint32_t rowPosition = flip ? imageOffset + (height - h) * rowSize : imageOffset; + //Serial.print("skip "); Serial.println(rowPosition - bytes_read); + bytes_read += skip(client, rowPosition - bytes_read); + for (uint16_t row = 0; row < h; row++, rowPosition += rowSize) // for each line + { + if (!connection_ok || !(client.connected() || client.available())) break; + delay(1); // yield() to avoid WDT + uint32_t in_remain = rowSize; + uint32_t in_idx = 0; + uint32_t in_bytes = 0; + uint8_t in_byte = 0; // for depth <= 8 + uint8_t in_bits = 0; // for depth <= 8 + uint16_t color = GxEPD_WHITE; + for (uint16_t col = 0; col < w; col++) // for each pixel + { + yield(); + if (!connection_ok || !(client.connected() || client.available())) break; + // Time to read more pixel data? + if (in_idx >= in_bytes) // ok, exact match for 24bit also (size IS multiple of 3) + { + uint32_t get = in_remain > sizeof(input_buffer) ? sizeof(input_buffer) : in_remain; + uint32_t got = read8n(client, input_buffer, get); + while ((got < get) && connection_ok) + { + //Serial.print("got "); Serial.print(got); Serial.print(" < "); Serial.print(get); Serial.print(" @ "); Serial.println(bytes_read); + uint32_t gotmore = read8n(client, input_buffer + got, get - got); + got += gotmore; + connection_ok = gotmore > 0; + } + in_bytes = got; + in_remain -= got; + bytes_read += got; + } + if (!connection_ok) + { + Serial.print("Error: got no more after "); Serial.print(bytes_read); Serial.println(" bytes read!"); + break; + } + switch (depth) + { + case 24: + blue = input_buffer[in_idx++]; + green = input_buffer[in_idx++]; + red = input_buffer[in_idx++]; + whitish = with_color ? ((red > 0x80) && (green > 0x80) && (blue > 0x80)) : ((red + green + blue) > 3 * 0x80); // whitish + colored = (red > 0xF0) || ((green > 0xF0) && (blue > 0xF0)); // reddish or yellowish? + color = ((red & 0xF8) << 8) | ((green & 0xFC) << 3) | ((blue & 0xF8) >> 3); + break; + case 16: + { + uint8_t lsb = input_buffer[in_idx++]; + uint8_t msb = input_buffer[in_idx++]; + if (format == 0) // 555 + { + blue = (lsb & 0x1F) << 3; + green = ((msb & 0x03) << 6) | ((lsb & 0xE0) >> 2); + red = (msb & 0x7C) << 1; + color = ((red & 0xF8) << 8) | ((green & 0xFC) << 3) | ((blue & 0xF8) >> 3); + } + else // 565 + { + blue = (lsb & 0x1F) << 3; + green = ((msb & 0x07) << 5) | ((lsb & 0xE0) >> 3); + red = (msb & 0xF8); + color = (msb << 8) | lsb; + } + whitish = with_color ? ((red > 0x80) && (green > 0x80) && (blue > 0x80)) : ((red + green + blue) > 3 * 0x80); // whitish + colored = (red > 0xF0) || ((green > 0xF0) && (blue > 0xF0)); // reddish or yellowish? + } + break; + case 1: + case 4: + case 8: + { + if (0 == in_bits) + { + in_byte = input_buffer[in_idx++]; + in_bits = 8; + } + uint16_t pn = (in_byte >> bitshift) & bitmask; + whitish = mono_palette_buffer[pn / 8] & (0x1 << pn % 8); + colored = color_palette_buffer[pn / 8] & (0x1 << pn % 8); + in_byte <<= depth; + in_bits -= depth; + color = rgb_palette_buffer[pn]; + } + break; + } + if (with_color && has_multicolors) + { + // keep color + } + else if (whitish) + { + color = GxEPD_WHITE; + } + else if (colored && with_color) + { + color = GxEPD_COLORED; + } + else + { + color = GxEPD_BLACK; + } + uint16_t yrow = y + (flip ? h - row - 1 : row); + display.drawPixel(x + col, yrow, color); + } // end pixel + } // end line + } + Serial.print("bytes read "); Serial.println(bytes_read); + } + } + Serial.print("loaded in "); Serial.print(millis() - startTime); Serial.println(" ms"); + client.stop(); + if (!valid) + { + Serial.println("bitmap format not handled."); + } +} + PaperdinkUIClass Paperdink_UI; diff --git a/src/ui/ui_base.h b/src/ui/ui_base.h index 573e5c6..c94bd7c 100644 --- a/src/ui/ui_base.h +++ b/src/ui/ui_base.h @@ -5,26 +5,33 @@ class PaperdinkUIBaseClass { -public: -const GFXfont *font = &PAPERDINK_FONT_SML; -const GFXfont *font_bold = &PAPERDINK_FONT_SML_BOLD; -int primary_color = GxEPD_BLACK; -int secondary_color = GxEPD_WHITE; -int tertiary_color = GxEPD_BLACK; + public: + const GFXfont *font = &PAPERDINK_FONT_SML; + const GFXfont *font_bold = &PAPERDINK_FONT_SML_BOLD; + int primary_color = GxEPD_BLACK; + int secondary_color = GxEPD_WHITE; + int tertiary_color = GxEPD_BLACK; }; class PaperdinkUIClass : public PaperdinkUIBaseClass { -public: + public: -void display_grid(GxEPD2_GFX& display); + void display_grid(GxEPD2_GFX& display); -void display_text_center(GxEPD2_GFX& display, int16_t x, int16_t y, const char *string, int16_t w = 0, int16_t h = 0, const GFXfont *font = &PAPERDINK_FONT_SML, uint8_t color = GxEPD_BLACK, uint8_t size = 1); + void display_text_center(GxEPD2_GFX& display, int16_t x, int16_t y, const char *string, int16_t w = 0, int16_t h = 0, const GFXfont *font = &PAPERDINK_FONT_SML, uint8_t color = GxEPD_BLACK, uint8_t size = 1); -uint16_t read16(File& f); -uint32_t read32(File& f); -void display_bitmap_fs(GxEPD2_GFX& display, fs::FS &fs, const char *filename, int16_t x, int16_t y, bool with_color); + uint16_t read16(File& f); + uint16_t read16(WiFiClient& client); + uint32_t read32(File& f); + uint32_t read32(WiFiClient& client); + uint32_t skip(WiFiClient& client, int32_t bytes); + uint32_t read8n(WiFiClient& client, uint8_t* buffer, int32_t bytes); + + void display_bitmap_fs(GxEPD2_GFX& display, fs::FS &fs, const char *filename, int16_t x, int16_t y, bool with_color); + void display_bitmap_https(GxEPD2_GFX& display, const char* host, const int httpsPort, const char* path, const char* filename, int16_t x, int16_t y, bool with_color, const char* certificate = false); + }; extern PaperdinkUIClass Paperdink_UI;