From c59fe361082579f010038d39890140df8c42611a Mon Sep 17 00:00:00 2001 From: Thijs Triemstra Date: Wed, 28 Feb 2024 07:01:40 +0100 Subject: [PATCH 01/10] Update GH actions (#391) --- .github/workflows/main.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 9fee784..c7e1e19 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -13,20 +13,20 @@ jobs: example: [examples/SSD1306UiDemo, examples/SSD1306SimpleDemo, examples/SSD1306DrawingDemo, examples/SSD1306OTADemo, examples/SSD1306ClockDemo, examples/SSD1306TwoScreenDemo] steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Cache pip - uses: actions/cache@v2 + uses: actions/cache@v3 with: path: ~/.cache/pip key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }} restore-keys: ${{ runner.os }}-pip- - name: Cache PlatformIO - uses: actions/cache@v2 + uses: actions/cache@v3 with: path: ~/.platformio key: ${{ runner.os }}-${{ hashFiles('**/lockfiles') }} - name: Set up Python - uses: actions/setup-python@v2 + uses: actions/setup-python@v5 - name: Install PlatformIO run: | python -m pip install --upgrade pip From 546fe9b3b5053e03dcba8f3a149d61cf8a8858db Mon Sep 17 00:00:00 2001 From: Thijs Triemstra Date: Wed, 28 Feb 2024 20:20:35 +0100 Subject: [PATCH 02/10] Mention SH1106 in README (#392) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 636493c..519a199 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ [![PlatformIO Registry](https://badges.registry.platformio.org/packages/thingpulse/library/ESP8266%20and%20ESP32%20OLED%20driver%20for%20SSD1306%20displays.svg)](https://registry.platformio.org/libraries/thingpulse/ESP8266%20and%20ESP32%20OLED%20driver%20for%20SSD1306%20displays) [![Build Status](https://github.com/ThingPulse/esp8266-oled-ssd1306/actions/workflows/main.yml/badge.svg)](https://github.com/ThingPulse/esp8266-oled-ssd1306/actions) -This is a driver for SSD1306 128x64, 128x32, 64x48 and 64x32 OLED displays running on the Arduino/ESP8266 & ESP32 and mbed-os platforms. +This is a driver for SSD1306 and SH1106 128x64, 128x32, 64x48 and 64x32 OLED displays running on the Arduino/ESP8266 & ESP32 and mbed-os platforms. Can be used with either the I2C or SPI version of the display. This library drives the OLED display included in the [ThingPulse IoT starter kit](https://thingpulse.com/product/esp8266-iot-electronics-starter-kit-weatherstation-planespotter-worldclock/) aka classic kit aka weather station kit. From 7782bc3d0715d683c29a9ef707b7598525865c38 Mon Sep 17 00:00:00 2001 From: Rop Gonggrijp Date: Sun, 10 Mar 2024 10:28:42 +0100 Subject: [PATCH 03/10] Fix drawLogBuffer for scrolling (#394) When logBuffer has logBufferMaxLines, the drawing needs to start shifted up by displayHeight % lineHeight so that the first line drops off a bit, and not the last. Now printing to display really just works. (I moved the `length++` and removed the `else` because both sides of the condition started with it.) --- src/OLEDDisplay.cpp | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/OLEDDisplay.cpp b/src/OLEDDisplay.cpp index 6c4f332..3b327c0 100644 --- a/src/OLEDDisplay.cpp +++ b/src/OLEDDisplay.cpp @@ -829,25 +829,27 @@ void OLEDDisplay::drawLogBuffer(uint16_t xMove, uint16_t yMove) { uint16_t line = 0; uint16_t lastPos = 0; + // If the lineHeight and the display height are not cleanly divisible, we need + // to start off the screen when the buffer has logBufferMaxLines so that the + // first line, and not the last line, drops off. + uint16_t shiftUp = (this->logBufferLine == this->logBufferMaxLines) ? displayHeight % lineHeight : 0; + for (uint16_t i=0;ilogBufferFilled;i++){ + length++; // Everytime we have a \n print if (this->logBuffer[i] == 10) { - length++; // Draw string on line `line` from lastPos to length // Passing 0 as the lenght because we are in TEXT_ALIGN_LEFT - drawStringInternal(xMove, yMove + (line++) * lineHeight, &this->logBuffer[lastPos], length, 0, false); + drawStringInternal(xMove, yMove - shiftUp + (line++) * lineHeight, &this->logBuffer[lastPos], length, 0, false); // Remember last pos lastPos = i; // Reset length length = 0; - } else { - // Count chars until next linebreak - length++; } } // Draw the remaining string if (length > 0) { - drawStringInternal(xMove, yMove + line * lineHeight, &this->logBuffer[lastPos], length, 0, false); + drawStringInternal(xMove, yMove - shiftUp + line * lineHeight, &this->logBuffer[lastPos], length, 0, false); } } From 1da41d956b43560a19e08cf5df2b3c25065ec088 Mon Sep 17 00:00:00 2001 From: Rop Gonggrijp Date: Sun, 10 Mar 2024 10:29:35 +0100 Subject: [PATCH 04/10] Added drawLogBuffer(0,0) and display() at end of write() (#389) * Added drawLogBuffer(0,0) and display() at end of write() Now print, println and printf "just work", while display not refreshed every character when a string of characters is written, only at the end. * The assumption that chars are at most twice as high as they're wide was too optimistic * Remove the now unnecessary commands from DrawingDemo --- .../SSD1306DrawingDemo/SSD1306DrawingDemo.ino | 11 +- src/OLEDDisplay.cpp | 132 ++++++++++-------- src/OLEDDisplay.h | 1 + 3 files changed, 73 insertions(+), 71 deletions(-) diff --git a/examples/SSD1306DrawingDemo/SSD1306DrawingDemo.ino b/examples/SSD1306DrawingDemo/SSD1306DrawingDemo.ino index d684e7d..eb1d30f 100644 --- a/examples/SSD1306DrawingDemo/SSD1306DrawingDemo.ino +++ b/examples/SSD1306DrawingDemo/SSD1306DrawingDemo.ino @@ -171,10 +171,6 @@ void drawCircle(void) { } void printBuffer(void) { - // Initialize the log buffer - // allocate memory to store 8 lines of text and 30 chars per line. - display.setLogBuffer(5, 30); - // Some test data const char* test[] = { "Hello", @@ -189,15 +185,10 @@ void printBuffer(void) { "scrolling is", "working" }; - + display.clear(); for (uint8_t i = 0; i < 11; i++) { - display.clear(); // Print to the screen display.println(test[i]); - // Draw it to the internal screen buffer - display.drawLogBuffer(0, 0); - // Display it on the screen - display.display(); delay(500); } } diff --git a/src/OLEDDisplay.cpp b/src/OLEDDisplay.cpp index 3b327c0..ec4576d 100644 --- a/src/OLEDDisplay.cpp +++ b/src/OLEDDisplay.cpp @@ -32,7 +32,6 @@ /* * TODO Helmut * - test/finish dislplay.printf() on mbed-os - * - Finish _putc with drawLogBuffer when running display */ #include "OLEDDisplay.h" @@ -42,6 +41,7 @@ OLEDDisplay::OLEDDisplay() { displayWidth = 128; displayHeight = 64; displayBufferSize = displayWidth * displayHeight / 8; + inhibitDrawLogBuffer = false; color = WHITE; geometry = GEOMETRY_128_64; textAlignment = TEXT_ALIGN_LEFT; @@ -879,53 +879,72 @@ bool OLEDDisplay::setLogBuffer(uint16_t lines, uint16_t chars){ } size_t OLEDDisplay::write(uint8_t c) { - if (this->logBufferSize > 0) { - // Don't waste space on \r\n line endings, dropping \r - if (c == 13) return 1; - - // convert UTF-8 character to font table index - c = (this->fontTableLookupFunction)(c); - // drop unknown character - if (c == 0) return 1; - - bool maxLineNotReached = this->logBufferLine < this->logBufferMaxLines; - bool bufferNotFull = this->logBufferFilled < this->logBufferSize; - - // Can we write to the buffer? - if (bufferNotFull && maxLineNotReached) { - this->logBuffer[logBufferFilled] = c; - this->logBufferFilled++; - // Keep track of lines written - if (c == 10) this->logBufferLine++; - } else { - // Max line number is reached - if (!maxLineNotReached) this->logBufferLine--; - - // Find the end of the first line - uint16_t firstLineEnd = 0; - for (uint16_t i=0;ilogBufferFilled;i++) { - if (this->logBuffer[i] == 10){ - // Include last char too - firstLineEnd = i + 1; - break; - } - } - // If there was a line ending - if (firstLineEnd > 0) { - // Calculate the new logBufferFilled value - this->logBufferFilled = logBufferFilled - firstLineEnd; - // Now we move the lines infront of the buffer - memcpy(this->logBuffer, &this->logBuffer[firstLineEnd], logBufferFilled); - } else { - // Let's reuse the buffer if it was full - if (!bufferNotFull) { - this->logBufferFilled = 0; - }// else { - // Nothing to do here - //} + if (!fontData) + return 1; + + // Create a logBuffer if there isn't one + if (!logBufferSize) { + uint8_t textHeight = pgm_read_byte(fontData + HEIGHT_POS); + uint16_t lines = this->displayHeight / textHeight; + uint16_t chars = 3 * (this->displayWidth / textHeight); + + if (this->displayHeight % textHeight) + lines++; + if (this->displayWidth % textHeight) + chars++; + setLogBuffer(lines, chars); + } + + // Don't waste space on \r\n line endings, dropping \r + if (c == 13) return 1; + + // convert UTF-8 character to font table index + c = (this->fontTableLookupFunction)(c); + // drop unknown character + if (c == 0) return 1; + + bool maxLineNotReached = this->logBufferLine < this->logBufferMaxLines; + bool bufferNotFull = this->logBufferFilled < this->logBufferSize; + + // Can we write to the buffer? + if (bufferNotFull && maxLineNotReached) { + this->logBuffer[logBufferFilled] = c; + this->logBufferFilled++; + // Keep track of lines written + if (c == 10) this->logBufferLine++; + } else { + // Max line number is reached + if (!maxLineNotReached) this->logBufferLine--; + + // Find the end of the first line + uint16_t firstLineEnd = 0; + for (uint16_t i=0;ilogBufferFilled;i++) { + if (this->logBuffer[i] == 10){ + // Include last char too + firstLineEnd = i + 1; + break; } - write(c); } + // If there was a line ending + if (firstLineEnd > 0) { + // Calculate the new logBufferFilled value + this->logBufferFilled = logBufferFilled - firstLineEnd; + // Now we move the lines infront of the buffer + memcpy(this->logBuffer, &this->logBuffer[firstLineEnd], logBufferFilled); + } else { + // Let's reuse the buffer if it was full + if (!bufferNotFull) { + this->logBufferFilled = 0; + }// else { + // Nothing to do here + //} + } + write(c); + } + if (!this->inhibitDrawLogBuffer) { + clear(); + drawLogBuffer(0, 0); + display(); } // We are always writing all uint8_t to the buffer return 1; @@ -934,29 +953,20 @@ size_t OLEDDisplay::write(uint8_t c) { size_t OLEDDisplay::write(const char* str) { if (str == NULL) return 0; size_t length = strlen(str); + // If we write a string, only do the drawLogBuffer at the end, not every time we write a char + this->inhibitDrawLogBuffer = true; for (size_t i = 0; i < length; i++) { write(str[i]); } + this->inhibitDrawLogBuffer = false; + clear(); + drawLogBuffer(0, 0); + display(); return length; } #ifdef __MBED__ int OLEDDisplay::_putc(int c) { - - if (!fontData) - return 1; - if (!logBufferSize) { - uint8_t textHeight = pgm_read_byte(fontData + HEIGHT_POS); - uint16_t lines = this->displayHeight / textHeight; - uint16_t chars = 2 * (this->displayWidth / textHeight); - - if (this->displayHeight % textHeight) - lines++; - if (this->displayWidth % textHeight) - chars++; - setLogBuffer(lines, chars); - } - return this->write((uint8_t)c); } #endif diff --git a/src/OLEDDisplay.h b/src/OLEDDisplay.h index 12cc0c3..b7c302d 100644 --- a/src/OLEDDisplay.h +++ b/src/OLEDDisplay.h @@ -364,6 +364,7 @@ class OLEDDisplay : public Stream { uint16_t logBufferLine; uint16_t logBufferMaxLines; char *logBuffer; + bool inhibitDrawLogBuffer; // the header size of the buffer used, e.g. for the SPI command header From c0758b67efda7cdd45395b6999c0871de0544192 Mon Sep 17 00:00:00 2001 From: Rop Gonggrijp Date: Mon, 11 Mar 2024 20:37:10 +0100 Subject: [PATCH 05/10] Implement cls(), document Print functionality (#397) There was no previous way for the user to empty the logBuffer, cls() fixes that. Also the documentation now explains the Print functionality and how it relates to the rest of the functions. --- README.md | 19 +++++++++++++++++++ src/OLEDDisplay.cpp | 7 +++++++ src/OLEDDisplay.h | 23 ++++++++++++++++++----- 3 files changed, 44 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 519a199..ff4d8a5 100644 --- a/README.md +++ b/README.md @@ -262,6 +262,25 @@ void setTextAlignment(OLEDDISPLAY_TEXT_ALIGNMENT textAlignment); void setFont(const uint8_t* fontData); ``` +## Arduino `Print` functionality + +Because this class has been "derived" from Arduino's `Print` class, you can use the functions it provides. In plain language, this means that you can use `print`, `println` and `printf` to the display. Internally, a buffer holds the text that was printed to the display previously (that would still fit on the display) and every time you print something, this buffer is put on the screen, using the functions from the previous section. + +What that means is that printing using `print` and "manually" putting things on the display are somewhat mutually exclusive: as soon as you print, everything that was on the display already is gone and only what you put there before with `print`, `println` or `printf` remains. Still, using `print` is a very simple way to put something on the display quickly. + +One extra function is provided: `cls()` +```cpp +// cls() will clear the display immediately and empty the logBuffer, meaning +// the next print statement will print at the top of the display again. +// cls() should not be confused with clear(), which only clears the internal +// graphics buffer, which can then be shown on the display with display(). +void cls(); +``` + +  + +
+ ## Ui Library (OLEDDisplayUi) The Ui Library is used to provide a basic set of user interface elements called `Frames` and `Overlays`. A `Frame` is used to provide diff --git a/src/OLEDDisplay.cpp b/src/OLEDDisplay.cpp index ec4576d..db7174c 100644 --- a/src/OLEDDisplay.cpp +++ b/src/OLEDDisplay.cpp @@ -861,6 +861,13 @@ uint16_t OLEDDisplay::getHeight(void) { return displayHeight; } +void OLEDDisplay::cls() { + clear(); + this->logBufferFilled = 0; + this->logBufferLine = 0; + display(); +} + bool OLEDDisplay::setLogBuffer(uint16_t lines, uint16_t chars){ if (logBuffer != NULL) free(logBuffer); uint16_t size = lines * chars; diff --git a/src/OLEDDisplay.h b/src/OLEDDisplay.h index b7c302d..20c4fca 100644 --- a/src/OLEDDisplay.h +++ b/src/OLEDDisplay.h @@ -311,14 +311,27 @@ class OLEDDisplay : public Stream { // Clear the local pixel buffer void clear(void); - // Log buffer implementation - - // This will define the lines and characters you can - // print to the screen. When you exeed the buffer size (lines * chars) - // the output may be truncated due to the size constraint. + // Print class device + + // Because this display class is "derived" from Arduino's Print class, + // various function that work on it also work here. These functions include + // print, println and printf. + + // cls() will clear the display immediately and empty the logBuffer, meaning + // the next print statement will print at the top of the display again. + // cls() should not be confused with clear(), which only clears the internal + // graphics buffer, which can then be shown on the display with display(). + void cls(); + + // This will define the lines and characters you can print to the screen. + // When you exeed the buffer size (lines * chars) the output may be + // truncated due to the size constraint. (Automatically called with the + // correct parameters when you first print to the display.) bool setLogBuffer(uint16_t lines, uint16_t chars); // Draw the log buffer at position (x, y) + // + // (Automatically called with you use print, println or printf) void drawLogBuffer(uint16_t x, uint16_t y); // Get screen geometry From 510b31a3a20cd5ef49fdca90e6358d8ce6d3e728 Mon Sep 17 00:00:00 2001 From: Rop Gonggrijp Date: Mon, 11 Mar 2024 20:38:34 +0100 Subject: [PATCH 06/10] More printing and scrolling fixes (#395) * logBuffer now stores max line length * write() rewritten to discard all but \n past that length * buffer cannot fill up prematurely * write() partly rewritten for clarity, no more re-entry when full --- src/OLEDDisplay.cpp | 74 +++++++++++++++++++++++++-------------------- src/OLEDDisplay.h | 1 + 2 files changed, 42 insertions(+), 33 deletions(-) diff --git a/src/OLEDDisplay.cpp b/src/OLEDDisplay.cpp index db7174c..0bb38b7 100644 --- a/src/OLEDDisplay.cpp +++ b/src/OLEDDisplay.cpp @@ -870,11 +870,12 @@ void OLEDDisplay::cls() { bool OLEDDisplay::setLogBuffer(uint16_t lines, uint16_t chars){ if (logBuffer != NULL) free(logBuffer); - uint16_t size = lines * chars; + uint16_t size = lines * (chars + 1); // +1 is for \n if (size > 0) { this->logBufferLine = 0; // Lines printed this->logBufferFilled = 0; // Nothing stored yet this->logBufferMaxLines = lines; // Lines max printable + this->logBufferLineLen = chars; // Chars per line this->logBufferSize = size; // Total number of characters the buffer can hold this->logBuffer = (char *) malloc(size * sizeof(uint8_t)); if(!this->logBuffer) { @@ -893,12 +894,10 @@ size_t OLEDDisplay::write(uint8_t c) { if (!logBufferSize) { uint8_t textHeight = pgm_read_byte(fontData + HEIGHT_POS); uint16_t lines = this->displayHeight / textHeight; - uint16_t chars = 3 * (this->displayWidth / textHeight); + uint16_t chars = 5 * (this->displayWidth / textHeight); if (this->displayHeight % textHeight) lines++; - if (this->displayWidth % textHeight) - chars++; setLogBuffer(lines, chars); } @@ -910,50 +909,59 @@ size_t OLEDDisplay::write(uint8_t c) { // drop unknown character if (c == 0) return 1; - bool maxLineNotReached = this->logBufferLine < this->logBufferMaxLines; - bool bufferNotFull = this->logBufferFilled < this->logBufferSize; + bool maxLineReached = this->logBufferLine >= this->logBufferMaxLines; + bool bufferFull = this->logBufferFilled >= this->logBufferSize; - // Can we write to the buffer? - if (bufferNotFull && maxLineNotReached) { - this->logBuffer[logBufferFilled] = c; - this->logBufferFilled++; - // Keep track of lines written - if (c == 10) this->logBufferLine++; - } else { - // Max line number is reached - if (!maxLineNotReached) this->logBufferLine--; - - // Find the end of the first line + // Can we write to the buffer? If not, make space. + if (bufferFull || maxLineReached) { + // See if we can chop off the first line uint16_t firstLineEnd = 0; - for (uint16_t i=0;ilogBufferFilled;i++) { + for (uint16_t i = 0; i < this->logBufferFilled; i++) { if (this->logBuffer[i] == 10){ // Include last char too firstLineEnd = i + 1; + // Calculate the new logBufferFilled value + this->logBufferFilled = logBufferFilled - firstLineEnd; + // Now move other lines to front of the buffer + memcpy(this->logBuffer, &this->logBuffer[firstLineEnd], logBufferFilled); + // And voila, buffer one line shorter + this->logBufferLine--; break; } } - // If there was a line ending - if (firstLineEnd > 0) { - // Calculate the new logBufferFilled value - this->logBufferFilled = logBufferFilled - firstLineEnd; - // Now we move the lines infront of the buffer - memcpy(this->logBuffer, &this->logBuffer[firstLineEnd], logBufferFilled); - } else { - // Let's reuse the buffer if it was full - if (!bufferNotFull) { - this->logBufferFilled = 0; - }// else { - // Nothing to do here - //} + // In we can't take off first line, we just empty the buffer + if (!firstLineEnd) { + this->logBufferFilled = 0; + this->logBufferLine = 0; } - write(c); } + + // So now we know for sure we have space in the buffer + + // Find the length of the last line + uint16_t lastLineLen= 0; + for (uint16_t i = 0; i < this->logBufferFilled; i++) { + lastLineLen++; + if (this->logBuffer[i] == 10) lastLineLen = 0; + } + // if last line is max length, ignore anything but linebreaks + if (lastLineLen >= this->logBufferLineLen) { + if (c != 10) return 1; + } + + // Write to buffer + this->logBuffer[this->logBufferFilled++] = c; + // Keep track of lines written + if (c == 10) this->logBufferLine++; + + // Draw to screen unless we're writing a whole string at a time if (!this->inhibitDrawLogBuffer) { clear(); drawLogBuffer(0, 0); display(); } - // We are always writing all uint8_t to the buffer + + // We are always claim we printed it all return 1; } diff --git a/src/OLEDDisplay.h b/src/OLEDDisplay.h index 20c4fca..35c87dd 100644 --- a/src/OLEDDisplay.h +++ b/src/OLEDDisplay.h @@ -376,6 +376,7 @@ class OLEDDisplay : public Stream { uint16_t logBufferFilled; uint16_t logBufferLine; uint16_t logBufferMaxLines; + uint16_t logBufferLineLen; char *logBuffer; bool inhibitDrawLogBuffer; From 344fb4969490166c69d486dff7d49da4d56d5960 Mon Sep 17 00:00:00 2001 From: Rop Gonggrijp Date: Tue, 12 Mar 2024 13:26:21 +0100 Subject: [PATCH 07/10] Minor clarification (#398) Explain where we deviate from what user might expect. --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index ff4d8a5..b75595d 100644 --- a/README.md +++ b/README.md @@ -275,6 +275,8 @@ One extra function is provided: `cls()` // cls() should not be confused with clear(), which only clears the internal // graphics buffer, which can then be shown on the display with display(). void cls(); + +> _Note that printing to the display, contrary to what you might expect, does not wrap your lines, so everything on a line that doesn't fit on the screen is cut off._ ```   From 2ef54280a62e74e18316a129ffeb146a1ccafb8b Mon Sep 17 00:00:00 2001 From: Rop Gonggrijp Date: Sun, 17 Mar 2024 08:18:25 +0100 Subject: [PATCH 08/10] More printing fixes (#399) * setLogBuffer needs to be re-called (and past buffer cleared) every time a `setFont` happens, as this changes the number of lines and chars. It now does not take arguments anymore and does things internally and is clearer about when it gives up. * calculation of shiftUp for when on last line was wrong * setLogBuffer() and drawLogBuffer() old versions with arguments deprecated, new versions protected. * Made no-op setLogBuffer return true to pass compiler error --- src/OLEDDisplay.cpp | 77 ++++++++++++++++++++++++++++++--------------- src/OLEDDisplay.h | 12 ++++--- 2 files changed, 59 insertions(+), 30 deletions(-) diff --git a/src/OLEDDisplay.cpp b/src/OLEDDisplay.cpp index 0bb38b7..a1c0a9d 100644 --- a/src/OLEDDisplay.cpp +++ b/src/OLEDDisplay.cpp @@ -752,6 +752,8 @@ void OLEDDisplay::setTextAlignment(OLEDDISPLAY_TEXT_ALIGNMENT textAlignment) { void OLEDDisplay::setFont(const uint8_t *fontData) { this->fontData = fontData; + // New font, so must recalculate. Whatever was there is gone at next print. + setLogBuffer(); } void OLEDDisplay::displayOn(void) { @@ -820,6 +822,10 @@ void OLEDDisplay::clear(void) { } void OLEDDisplay::drawLogBuffer(uint16_t xMove, uint16_t yMove) { + Serial.println("[deprecated] Print functionality now handles buffer management automatically. This is a no-op."); +} + +void OLEDDisplay::drawLogBuffer() { uint16_t lineHeight = pgm_read_byte(fontData + HEIGHT_POS); // Always align left setTextAlignment(TEXT_ALIGN_LEFT); @@ -832,7 +838,7 @@ void OLEDDisplay::drawLogBuffer(uint16_t xMove, uint16_t yMove) { // If the lineHeight and the display height are not cleanly divisible, we need // to start off the screen when the buffer has logBufferMaxLines so that the // first line, and not the last line, drops off. - uint16_t shiftUp = (this->logBufferLine == this->logBufferMaxLines) ? displayHeight % lineHeight : 0; + uint16_t shiftUp = (this->logBufferLine == this->logBufferMaxLines) ? (lineHeight - (displayHeight % lineHeight)) % lineHeight : 0; for (uint16_t i=0;ilogBufferFilled;i++){ length++; @@ -840,7 +846,7 @@ void OLEDDisplay::drawLogBuffer(uint16_t xMove, uint16_t yMove) { if (this->logBuffer[i] == 10) { // Draw string on line `line` from lastPos to length // Passing 0 as the lenght because we are in TEXT_ALIGN_LEFT - drawStringInternal(xMove, yMove - shiftUp + (line++) * lineHeight, &this->logBuffer[lastPos], length, 0, false); + drawStringInternal(0, 0 - shiftUp + (line++) * lineHeight, &this->logBuffer[lastPos], length, 0, false); // Remember last pos lastPos = i; // Reset length @@ -849,7 +855,7 @@ void OLEDDisplay::drawLogBuffer(uint16_t xMove, uint16_t yMove) { } // Draw the remaining string if (length > 0) { - drawStringInternal(xMove, yMove - shiftUp + line * lineHeight, &this->logBuffer[lastPos], length, 0, false); + drawStringInternal(0, 0 - shiftUp + line * lineHeight, &this->logBuffer[lastPos], length, 0, false); } } @@ -868,21 +874,44 @@ void OLEDDisplay::cls() { display(); } -bool OLEDDisplay::setLogBuffer(uint16_t lines, uint16_t chars){ - if (logBuffer != NULL) free(logBuffer); +bool OLEDDisplay::setLogBuffer(uint16_t lines, uint16_t chars) { + Serial.println("[deprecated] Print functionality now handles buffer management automatically. This is a no-op."); + return true; +} + +bool OLEDDisplay::setLogBuffer(){ + // don't know how big we need it without a font set. + if (!fontData) + return false; + + // we're always starting over + if (logBuffer != NULL) + free(logBuffer); + + // figure out how big it needs to be + uint8_t textHeight = pgm_read_byte(fontData + HEIGHT_POS); + if (!textHeight) + return false; // Prevent division by zero crashes + uint16_t lines = this->displayHeight / textHeight + (this->displayHeight % textHeight ? 1 : 0); + uint16_t chars = 5 * (this->displayWidth / textHeight); uint16_t size = lines * (chars + 1); // +1 is for \n - if (size > 0) { - this->logBufferLine = 0; // Lines printed - this->logBufferFilled = 0; // Nothing stored yet - this->logBufferMaxLines = lines; // Lines max printable - this->logBufferLineLen = chars; // Chars per line - this->logBufferSize = size; // Total number of characters the buffer can hold - this->logBuffer = (char *) malloc(size * sizeof(uint8_t)); - if(!this->logBuffer) { - DEBUG_OLEDDISPLAY("[OLEDDISPLAY][setLogBuffer] Not enough memory to create log buffer\n"); - return false; - } + + // Something weird must have happened + if (size == 0) + return false; + + // All good, initialize logBuffer + this->logBufferLine = 0; // Lines printed + this->logBufferFilled = 0; // Nothing stored yet + this->logBufferMaxLines = lines; // Lines max printable + this->logBufferLineLen = chars; // Chars per line + this->logBufferSize = size; // Total number of characters the buffer can hold + this->logBuffer = (char *) malloc(size * sizeof(uint8_t)); + if(!this->logBuffer) { + DEBUG_OLEDDISPLAY("[OLEDDISPLAY][setLogBuffer] Not enough memory to create log buffer\n"); + return false; } + return true; } @@ -892,13 +921,9 @@ size_t OLEDDisplay::write(uint8_t c) { // Create a logBuffer if there isn't one if (!logBufferSize) { - uint8_t textHeight = pgm_read_byte(fontData + HEIGHT_POS); - uint16_t lines = this->displayHeight / textHeight; - uint16_t chars = 5 * (this->displayWidth / textHeight); - - if (this->displayHeight % textHeight) - lines++; - setLogBuffer(lines, chars); + // Give up if we can't create a logBuffer somehow + if (!setLogBuffer()) + return 1; } // Don't waste space on \r\n line endings, dropping \r @@ -957,11 +982,11 @@ size_t OLEDDisplay::write(uint8_t c) { // Draw to screen unless we're writing a whole string at a time if (!this->inhibitDrawLogBuffer) { clear(); - drawLogBuffer(0, 0); + drawLogBuffer(); display(); } - // We are always claim we printed it all + // We always claim we printed it all return 1; } @@ -975,7 +1000,7 @@ size_t OLEDDisplay::write(const char* str) { } this->inhibitDrawLogBuffer = false; clear(); - drawLogBuffer(0, 0); + drawLogBuffer(); display(); return length; } diff --git a/src/OLEDDisplay.h b/src/OLEDDisplay.h index 35c87dd..80a3abc 100644 --- a/src/OLEDDisplay.h +++ b/src/OLEDDisplay.h @@ -323,10 +323,7 @@ class OLEDDisplay : public Stream { // graphics buffer, which can then be shown on the display with display(). void cls(); - // This will define the lines and characters you can print to the screen. - // When you exeed the buffer size (lines * chars) the output may be - // truncated due to the size constraint. (Automatically called with the - // correct parameters when you first print to the display.) + // Replaced by setLogBuffer() , which is protected bool setLogBuffer(uint16_t lines, uint16_t chars); // Draw the log buffer at position (x, y) @@ -401,6 +398,13 @@ class OLEDDisplay : public Stream { uint16_t drawStringInternal(int16_t xMove, int16_t yMove, const char* text, uint16_t textLength, uint16_t textWidth, bool utf8); + // (re)creates the logBuffer that printing uses to remember what was on the + // screen already + bool setLogBuffer(); + + // Draws the contents of the logBuffer to the screen + void drawLogBuffer(); + FontTableLookupFunction fontTableLookupFunction; }; From 906d0c5afeffa4f72862296e49f8548834b22a30 Mon Sep 17 00:00:00 2001 From: Rop Gonggrijp Date: Mon, 18 Mar 2024 10:32:15 +0100 Subject: [PATCH 09/10] Also accept char* pointer for fonts (#393) --- src/OLEDDisplay.cpp | 4 ++++ src/OLEDDisplay.h | 3 +++ 2 files changed, 7 insertions(+) diff --git a/src/OLEDDisplay.cpp b/src/OLEDDisplay.cpp index a1c0a9d..3a0c009 100644 --- a/src/OLEDDisplay.cpp +++ b/src/OLEDDisplay.cpp @@ -756,6 +756,10 @@ void OLEDDisplay::setFont(const uint8_t *fontData) { setLogBuffer(); } +void OLEDDisplay::setFont(const char *fontData) { + setFont(static_cast(reinterpret_cast(fontData))); +} + void OLEDDisplay::displayOn(void) { sendCommand(DISPLAYON); } diff --git a/src/OLEDDisplay.h b/src/OLEDDisplay.h index 80a3abc..474b163 100644 --- a/src/OLEDDisplay.h +++ b/src/OLEDDisplay.h @@ -271,6 +271,9 @@ class OLEDDisplay : public Stream { // ArialMT_Plain_10, ArialMT_Plain_16, ArialMT_Plain_24 void setFont(const uint8_t *fontData); + // Set the current font when supplied as a char* instead of a uint8_t* + void setFont(const char *fontData); + // Set the function that will convert utf-8 to font table index void setFontTableLookupFunction(FontTableLookupFunction function); From d3b23d0397235871dee65c70333c97a8070da0f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcel=20St=C3=B6r?= Date: Fri, 29 Mar 2024 10:17:36 +0100 Subject: [PATCH 10/10] Bump version --- library.json | 2 +- library.properties | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/library.json b/library.json index 53fb48a..757885e 100644 --- a/library.json +++ b/library.json @@ -1,6 +1,6 @@ { "name": "ESP8266 and ESP32 OLED driver for SSD1306 displays", - "version": "4.4.1", + "version": "4.5.0", "keywords": "ssd1306, oled, display, i2c", "description": "I2C display driver for SSD1306 OLED displays connected to ESP8266, ESP32, Mbed-OS", "license": "MIT", diff --git a/library.properties b/library.properties index f3dceec..c732e23 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=ESP8266 and ESP32 OLED driver for SSD1306 displays -version=4.4.1 +version=4.5.0 author=ThingPulse, Fabrice Weinberg maintainer=ThingPulse sentence=I2C display driver for SSD1306 OLED displays connected to ESP8266, ESP32, Mbed-OS