From 2a3bdf8fe6c8c3ded81faea90ddbed8cdd98a75d Mon Sep 17 00:00:00 2001 From: Unknown <gijs.noorlander@gmail.com> Date: Sat, 3 Feb 2018 20:42:07 +0100 Subject: [PATCH] Merged lots of PR + fix some memory leaks Library did some allocs without free and lots of un-initialized variables. Applied pull requests from esp8266-oled-ssd1306: squix78/esp8266-oled-ssd1306#169 squix78/esp8266-oled-ssd1306#157 squix78/esp8266-oled-ssd1306#144 And applied the suggestions from issues: squix78/esp8266-oled-ssd1306#170 squix78/esp8266-oled-ssd1306#161 Support multiple display resolutions Applied PR from esp8266-oled-ssd1306: squix78/esp8266-oled-ssd1306#133 Better Brightness / Contrast control Suggestions taken from this issue: squix78/esp8266-oled-ssd1306#134 It is now the same version as being used in ESPeasy. --- OLEDDisplay.cpp | 87 +++++++++++++++++++++++++++++------------------ OLEDDisplay.h | 33 +++++++++++++----- OLEDDisplayUi.cpp | 34 +++++++++--------- SSD1306Wire.h | 24 +++++++------ 4 files changed, 108 insertions(+), 70 deletions(-) diff --git a/OLEDDisplay.cpp b/OLEDDisplay.cpp index f8fc226..41af7c2 100644 --- a/OLEDDisplay.cpp +++ b/OLEDDisplay.cpp @@ -27,24 +27,32 @@ #include "OLEDDisplay.h" +OLEDDisplay::~OLEDDisplay() { + end(); +} + bool OLEDDisplay::init() { if (!this->connect()) { DEBUG_OLEDDISPLAY("[OLEDDISPLAY][init] Can't establish connection to display\n"); return false; } + if(this->buffer==NULL) { this->buffer = (uint8_t*) malloc(sizeof(uint8_t) * DISPLAY_BUFFER_SIZE); if(!this->buffer) { DEBUG_OLEDDISPLAY("[OLEDDISPLAY][init] Not enough memory to create display\n"); return false; } + } #ifdef OLEDDISPLAY_DOUBLE_BUFFER + if(this->buffer_back==NULL) { this->buffer_back = (uint8_t*) malloc(sizeof(uint8_t) * DISPLAY_BUFFER_SIZE); if(!this->buffer_back) { DEBUG_OLEDDISPLAY("[OLEDDISPLAY][init] Not enough memory to create back buffer\n"); free(this->buffer); return false; } + } #endif sendInitCommands(); @@ -54,10 +62,11 @@ bool OLEDDisplay::init() { } void OLEDDisplay::end() { - if (this->buffer) free(this->buffer); + if (this->buffer) { free(this->buffer); this->buffer = NULL; } #ifdef OLEDDISPLAY_DOUBLE_BUFFER - if (this->buffer_back) free(this->buffer_back); + if (this->buffer_back) { free(this->buffer_back); this->buffer_back = NULL; } #endif + if (this->logBuffer != NULL) { free(this->logBuffer); this->logBuffer = NULL; } } void OLEDDisplay::resetDisplay(void) { @@ -73,11 +82,11 @@ void OLEDDisplay::setColor(OLEDDISPLAY_COLOR color) { } void OLEDDisplay::setPixel(int16_t x, int16_t y) { - if (x >= 0 && x < 128 && y >= 0 && y < 64) { + if (x >= 0 && x < this->width() && y >= 0 && y < this->height()) { switch (color) { - case WHITE: buffer[x + (y / 8) * DISPLAY_WIDTH] |= (1 << (y & 7)); break; - case BLACK: buffer[x + (y / 8) * DISPLAY_WIDTH] &= ~(1 << (y & 7)); break; - case INVERSE: buffer[x + (y / 8) * DISPLAY_WIDTH] ^= (1 << (y & 7)); break; + case WHITE: buffer[x + (y / 8) * this->width()] |= (1 << (y & 7)); break; + case BLACK: buffer[x + (y / 8) * this->width()] &= ~(1 << (y & 7)); break; + case INVERSE: buffer[x + (y / 8) * this->width()] ^= (1 << (y & 7)); break; } } } @@ -222,21 +231,21 @@ void OLEDDisplay::fillCircle(int16_t x0, int16_t y0, int16_t radius) { } void OLEDDisplay::drawHorizontalLine(int16_t x, int16_t y, int16_t length) { - if (y < 0 || y >= DISPLAY_HEIGHT) { return; } + if (y < 0 || y >= this->height()) { return; } if (x < 0) { length += x; x = 0; } - if ( (x + length) > DISPLAY_WIDTH) { - length = (DISPLAY_WIDTH - x); + if ( (x + length) > this->width()) { + length = (this->width() - x); } if (length <= 0) { return; } uint8_t * bufferPtr = buffer; - bufferPtr += (y >> 3) * DISPLAY_WIDTH; + bufferPtr += (y >> 3) * this->width(); bufferPtr += x; uint8_t drawBit = 1 << (y & 7); @@ -255,15 +264,15 @@ void OLEDDisplay::drawHorizontalLine(int16_t x, int16_t y, int16_t length) { } void OLEDDisplay::drawVerticalLine(int16_t x, int16_t y, int16_t length) { - if (x < 0 || x >= DISPLAY_WIDTH) return; + if (x < 0 || x >= this->width()) return; if (y < 0) { length += y; y = 0; } - if ( (y + length) > DISPLAY_HEIGHT) { - length = (DISPLAY_HEIGHT - y); + if ( (y + length) > this->height()) { + length = (this->height() - y); } if (length <= 0) return; @@ -273,7 +282,7 @@ void OLEDDisplay::drawVerticalLine(int16_t x, int16_t y, int16_t length) { uint8_t drawBit; uint8_t *bufferPtr = buffer; - bufferPtr += (y >> 3) * DISPLAY_WIDTH; + bufferPtr += (y >> 3) * this->width(); bufferPtr += x; if (yOffset) { @@ -293,7 +302,7 @@ void OLEDDisplay::drawVerticalLine(int16_t x, int16_t y, int16_t length) { if (length < yOffset) return; length -= yOffset; - bufferPtr += DISPLAY_WIDTH; + bufferPtr += this->width(); } if (length >= 8) { @@ -303,14 +312,14 @@ void OLEDDisplay::drawVerticalLine(int16_t x, int16_t y, int16_t length) { drawBit = (color == WHITE) ? 0xFF : 0x00; do { *bufferPtr = drawBit; - bufferPtr += DISPLAY_WIDTH; + bufferPtr += this->width(); length -= 8; } while (length >= 8); break; case INVERSE: do { *bufferPtr = ~(*bufferPtr); - bufferPtr += DISPLAY_WIDTH; + bufferPtr += this->width(); length -= 8; } while (length >= 8); break; @@ -353,7 +362,7 @@ void OLEDDisplay::drawFastImage(int16_t xMove, int16_t yMove, int16_t width, int void OLEDDisplay::drawXbm(int16_t xMove, int16_t yMove, int16_t width, int16_t height, const char *xbm) { int16_t widthInXbm = (width + 7) / 8; - uint8_t data; + uint8_t data = 0; for(int16_t y = 0; y < height; y++) { for(int16_t x = 0; x < width; x++ ) { @@ -388,11 +397,13 @@ void OLEDDisplay::drawStringInternal(int16_t xMove, int16_t yMove, char* text, u case TEXT_ALIGN_RIGHT: xMove -= textWidth; break; + case TEXT_ALIGN_LEFT: + break; } // Don't draw anything if it is not on the screen. - if (xMove + textWidth < 0 || xMove > DISPLAY_WIDTH ) {return;} - if (yMove + textHeight < 0 || yMove > DISPLAY_HEIGHT) {return;} + if (xMove + textWidth < 0 || xMove > this->width() ) {return;} + if (yMove + textHeight < 0 || yMove > this->width() ) {return;} for (uint16_t j = 0; j < textLength; j++) { int16_t xPos = xMove + cursorX; @@ -545,9 +556,16 @@ void OLEDDisplay::normalDisplay(void) { sendCommand(NORMALDISPLAY); } -void OLEDDisplay::setContrast(char contrast) { +void OLEDDisplay::setContrast(char contrast, char precharge, char comdetect) { + sendCommand(SETPRECHARGE); //0xD9 + sendCommand(precharge); //0xF1 default, to lower the contrast, put 1-1F sendCommand(SETCONTRAST); - sendCommand(contrast); + sendCommand(contrast); // 0-255 + sendCommand(SETVCOMDETECT); //0xDB, (additionally needed to lower the contrast) + sendCommand(comdetect); //0x40 default, to lower the contrast, put 0 + sendCommand(DISPLAYALLON_RESUME); + sendCommand(NORMALDISPLAY); + sendCommand(DISPLAYON); } void OLEDDisplay::flipScreenVertically() { @@ -596,6 +614,7 @@ bool OLEDDisplay::setLogBuffer(uint16_t lines, uint16_t chars){ uint16_t size = lines * chars; if (size > 0) { this->logBufferLine = 0; // Lines printed + this->logBufferFilled = 0; // Nothing stored yet this->logBufferMaxLines = lines; // Lines max printable this->logBufferSize = size; // Total number of characters the buffer can hold this->logBuffer = (char *) malloc(size * sizeof(uint8_t)); @@ -670,7 +689,7 @@ void OLEDDisplay::sendInitCommands(void) { sendCommand(SETDISPLAYCLOCKDIV); sendCommand(0xF0); // Increase speed of the display max ~96Hz sendCommand(SETMULTIPLEX); - sendCommand(0x3F); + sendCommand(this->height() - 1); sendCommand(SETDISPLAYOFFSET); sendCommand(0x00); sendCommand(SETSTARTLINE); @@ -681,11 +700,13 @@ void OLEDDisplay::sendInitCommands(void) { sendCommand(SEGREMAP); sendCommand(COMSCANINC); sendCommand(SETCOMPINS); - sendCommand(0x12); + sendCommand(0x12); // according to the adafruit lib, sometimes this may need to be 0x02 sendCommand(SETCONTRAST); sendCommand(0xCF); sendCommand(SETPRECHARGE); sendCommand(0xF1); + sendCommand(SETVCOMDETECT); //0xDB, (additionally needed to lower the contrast) + sendCommand(0x40); //0x40 default, to lower the contrast, put 0 sendCommand(DISPLAYALLON_RESUME); sendCommand(NORMALDISPLAY); sendCommand(0x2e); // stop scroll @@ -694,8 +715,8 @@ void OLEDDisplay::sendInitCommands(void) { void inline OLEDDisplay::drawInternal(int16_t xMove, int16_t yMove, int16_t width, int16_t height, const char *data, uint16_t offset, uint16_t bytesInData) { if (width < 0 || height < 0) return; - if (yMove + height < 0 || yMove > DISPLAY_HEIGHT) return; - if (xMove + width < 0 || xMove > DISPLAY_WIDTH) return; + if (yMove + height < 0 || yMove > this->height()) return; + if (xMove + width < 0 || xMove > this->width()) return; uint8_t rasterHeight = 1 + ((height - 1) >> 3); // fast ceil(height / 8.0) int8_t yOffset = yMove & 7; @@ -717,13 +738,13 @@ void inline OLEDDisplay::drawInternal(int16_t xMove, int16_t yMove, int16_t widt byte currentByte = pgm_read_byte(data + offset + i); int16_t xPos = xMove + (i / rasterHeight); - int16_t yPos = ((yMove >> 3) + (i % rasterHeight)) * DISPLAY_WIDTH; + int16_t yPos = ((yMove >> 3) + (i % rasterHeight)) * this->width(); - int16_t yScreenPos = yMove + yOffset; +// int16_t yScreenPos = yMove + yOffset; int16_t dataPos = xPos + yPos; if (dataPos >= 0 && dataPos < DISPLAY_BUFFER_SIZE && - xPos >= 0 && xPos < DISPLAY_WIDTH ) { + xPos >= 0 && xPos < this->width() ) { if (yOffset >= 0) { switch (this->color) { @@ -731,11 +752,11 @@ void inline OLEDDisplay::drawInternal(int16_t xMove, int16_t yMove, int16_t widt case BLACK: buffer[dataPos] &= ~(currentByte << yOffset); break; case INVERSE: buffer[dataPos] ^= currentByte << yOffset; break; } - if (dataPos < (DISPLAY_BUFFER_SIZE - DISPLAY_WIDTH)) { + if (dataPos < (DISPLAY_BUFFER_SIZE - this->width())) { switch (this->color) { - case WHITE: buffer[dataPos + DISPLAY_WIDTH] |= currentByte >> (8 - yOffset); break; - case BLACK: buffer[dataPos + DISPLAY_WIDTH] &= ~(currentByte >> (8 - yOffset)); break; - case INVERSE: buffer[dataPos + DISPLAY_WIDTH] ^= currentByte >> (8 - yOffset); break; + case WHITE: buffer[dataPos + this->width()] |= currentByte >> (8 - yOffset); break; + case BLACK: buffer[dataPos + this->width()] &= ~(currentByte >> (8 - yOffset)); break; + case INVERSE: buffer[dataPos + this->width()] ^= currentByte >> (8 - yOffset); break; } } } else { diff --git a/OLEDDisplay.h b/OLEDDisplay.h index 81537a2..acd18ea 100644 --- a/OLEDDisplay.h +++ b/OLEDDisplay.h @@ -44,9 +44,13 @@ // Display settings -#define DISPLAY_WIDTH 128 -#define DISPLAY_HEIGHT 64 -#define DISPLAY_BUFFER_SIZE 1024 +#ifndef DISPLAY_WIDTH + #define DISPLAY_WIDTH 128 +#endif +#ifndef DISPLAY_HEIGHT + #define DISPLAY_HEIGHT 64 +#endif +#define DISPLAY_BUFFER_SIZE DISPLAY_WIDTH * DISPLAY_HEIGHT / 8 // Header Values #define JUMPTABLE_BYTES 4 @@ -109,7 +113,16 @@ enum OLEDDISPLAY_TEXT_ALIGNMENT { class OLEDDisplay : public Print { + private: + const int _width, _height; + public: + OLEDDisplay(const int width = DISPLAY_WIDTH, const int height = DISPLAY_HEIGHT) : _width(width), _height(height){ }; + virtual ~OLEDDisplay(); + + const int width(void) const { return _width; }; + const int height(void) const { return _height; }; + // Initialize the display bool init(); @@ -150,7 +163,7 @@ class OLEDDisplay : public Print { // Draw a lin vertically void drawVerticalLine(int16_t x, int16_t y, int16_t length); - // Draws a rounded progress bar with the outer dimensions given by width and height. Progress is + // Draws a rounded progress bar with the outer dimensions given by width and height. Progress is // a unsigned byte value between 0 and 100 void drawProgressBar(uint16_t x, uint16_t y, uint16_t width, uint16_t height, uint8_t progress); @@ -201,7 +214,9 @@ class OLEDDisplay : public Print { void normalDisplay(void); // Set display contrast - void setContrast(char contrast); + // really low brightness & contrast: contrast = 10, precharge = 5, comdetect = 0 + // normal brightness & contrast: contrast = 100 + void setContrast(char contrast, char precharge = 241, char comdetect = 64); // Turn the display upside down void flipScreenVertically(); @@ -226,10 +241,10 @@ class OLEDDisplay : public Print { size_t write(uint8_t c); size_t write(const char* s); - uint8_t *buffer; + uint8_t *buffer = NULL; #ifdef OLEDDISPLAY_DOUBLE_BUFFER - uint8_t *buffer_back; + uint8_t *buffer_back = NULL; #endif protected: @@ -247,10 +262,10 @@ class OLEDDisplay : public Print { char *logBuffer = NULL; // Send a command to the display (low level function) - virtual void sendCommand(uint8_t com) {}; + virtual void sendCommand(uint8_t com) {(void)com;}; // Connect to the display - virtual bool connect() {}; + virtual bool connect() { return false; }; // Send all the init commands void sendInitCommands(); diff --git a/OLEDDisplayUi.cpp b/OLEDDisplayUi.cpp index 3fb4326..976bbac 100644 --- a/OLEDDisplayUi.cpp +++ b/OLEDDisplayUi.cpp @@ -251,31 +251,31 @@ void OLEDDisplayUi::drawFrame(){ switch (this->state.frameState){ case IN_TRANSITION: { float progress = (float) this->state.ticksSinceLastStateSwitch / (float) this->ticksPerTransition; - int16_t x, y, x1, y1; + int16_t x = 0, y = 0, x1 = 0, y1 = 0; switch(this->frameAnimationDirection){ case SLIDE_LEFT: - x = -128 * progress; + x = -this->display->width() * progress; y = 0; - x1 = x + 128; + x1 = x + this->display->width(); y1 = 0; break; case SLIDE_RIGHT: - x = 128 * progress; + x = this->display->width() * progress; y = 0; - x1 = x - 128; + x1 = x - this->display->width(); y1 = 0; break; case SLIDE_UP: x = 0; - y = -64 * progress; + y = -this->display->height() * progress; x1 = 0; - y1 = y + 64; + y1 = y + this->display->height(); break; case SLIDE_DOWN: x = 0; - y = 64 * progress; + y = this->display->height() * progress; x1 = 0; - y1 = y - 64; + y1 = y - this->display->height(); break; } @@ -331,7 +331,7 @@ void OLEDDisplayUi::drawIndicator() { return; } - uint8_t posOfHighlightFrame; + uint8_t posOfHighlightFrame = 0; float indicatorFadeProgress = 0; // if the indicator needs to be slided in we want to @@ -362,25 +362,25 @@ void OLEDDisplayUi::drawIndicator() { uint16_t frameStartPos = (12 * frameCount / 2); const char *image; - uint16_t x,y; + uint16_t x = 0, y = 0; for (byte i = 0; i < this->frameCount; i++) { switch (this->indicatorPosition){ case TOP: y = 0 - (8 * indicatorFadeProgress); - x = 64 - frameStartPos + 12 * i; + x = (this->display->width() / 2) - frameStartPos + 12 * i; break; case BOTTOM: - y = 56 + (8 * indicatorFadeProgress); - x = 64 - frameStartPos + 12 * i; + y = (this->display->height() - 8) + (8 * indicatorFadeProgress); + x = (this->display->width() / 2) - frameStartPos + 12 * i; break; case RIGHT: - x = 120 + (8 * indicatorFadeProgress); - y = 32 - frameStartPos + 2 + 12 * i; + x = (this->display->width() - 8) + (8 * indicatorFadeProgress); + y = (this->display->height() / 2) - frameStartPos + 2 + 12 * i; break; case LEFT: x = 0 - (8 * indicatorFadeProgress); - y = 32 - frameStartPos + 2 + 12 * i; + y = (this->display->height() / 2) - frameStartPos + 2 + 12 * i; break; } diff --git a/SSD1306Wire.h b/SSD1306Wire.h index ac12bec..c22b714 100644 --- a/SSD1306Wire.h +++ b/SSD1306Wire.h @@ -38,7 +38,8 @@ class SSD1306Wire : public OLEDDisplay { uint8_t _scl; public: - SSD1306Wire(uint8_t _address, uint8_t _sda, uint8_t _scl) { + SSD1306Wire(uint8_t _address, uint8_t _sda, uint8_t _scl, int width = DISPLAY_WIDTH, int height = DISPLAY_HEIGHT) + : OLEDDisplay(width, height) { this->_address = _address; this->_sda = _sda; this->_scl = _scl; @@ -53,6 +54,7 @@ class SSD1306Wire : public OLEDDisplay { } void display(void) { + const int x_offset = (128 - this->width()) / 2; #ifdef OLEDDISPLAY_DOUBLE_BUFFER uint8_t minBoundY = ~0; uint8_t maxBoundY = 0; @@ -63,9 +65,9 @@ class SSD1306Wire : public OLEDDisplay { // Calculate the Y bounding box of changes // and copy buffer[pos] to buffer_back[pos]; - for (y = 0; y < (DISPLAY_HEIGHT / 8); y++) { - for (x = 0; x < DISPLAY_WIDTH; x++) { - uint16_t pos = x + y * DISPLAY_WIDTH; + for (y = 0; y < (this->height() / 8); y++) { + for (x = 0; x < this->width(); x++) { + uint16_t pos = x + y * this->width(); if (buffer[pos] != buffer_back[pos]) { minBoundY = _min(minBoundY, y); maxBoundY = _max(maxBoundY, y); @@ -80,11 +82,11 @@ class SSD1306Wire : public OLEDDisplay { // If the minBoundY wasn't updated // we can savely assume that buffer_back[pos] == buffer[pos] // holdes true for all values of pos - if (minBoundY == ~0) return; + if (minBoundY == (uint8_t)(~0)) return; sendCommand(COLUMNADDR); - sendCommand(minBoundX); - sendCommand(maxBoundX); + sendCommand(x_offset + minBoundX); + sendCommand(x_offset + maxBoundX); sendCommand(PAGEADDR); sendCommand(minBoundY); @@ -97,7 +99,7 @@ class SSD1306Wire : public OLEDDisplay { Wire.beginTransmission(_address); Wire.write(0x40); } - Wire.write(buffer[x + y * DISPLAY_WIDTH]); + Wire.write(buffer[x + y * this->width()]); k++; if (k == 16) { Wire.endTransmission(); @@ -113,12 +115,12 @@ class SSD1306Wire : public OLEDDisplay { #else sendCommand(COLUMNADDR); - sendCommand(0x0); - sendCommand(0x7F); + sendCommand(x_offset); + sendCommand(x_offset + (this->width() - 1)); sendCommand(PAGEADDR); sendCommand(0x0); - sendCommand(0x7); + sendCommand((this->height() / 8) - 1); for (uint16_t i=0; i < DISPLAY_BUFFER_SIZE; i++) { Wire.beginTransmission(this->_address); -- GitLab