diff --git a/OLEDDisplay.cpp b/OLEDDisplay.cpp index 9b171a0..9caf84f 100644 --- a/OLEDDisplay.cpp +++ b/OLEDDisplay.cpp @@ -27,24 +27,35 @@ #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) * displayBufferSize); + 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) * displayBufferSize); + 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 +65,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) { @@ -77,12 +89,11 @@ OLEDDISPLAY_COLOR OLEDDisplay::getColor() { } void OLEDDisplay::setPixel(int16_t x, int16_t y) { - if (x >= 0 && x < displayWidth && y >= 0 && y < displayHeight) { - + if (x >= 0 && x < this->width() && y >= 0 && y < this->height()) { switch (color) { - case WHITE: buffer[x + (y / 8) * displayWidth] |= (1 << (y & 7)); break; - case BLACK: buffer[x + (y / 8) * displayWidth] &= ~(1 << (y & 7)); break; - case INVERSE: buffer[x + (y / 8) * displayWidth] ^= (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; } } } @@ -227,21 +238,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 >= displayHeight) { return; } + if (y < 0 || y >= this->height()) { return; } if (x < 0) { length += x; x = 0; } - if ( (x + length) > displayWidth) { - length = (displayWidth - x); + if ( (x + length) > this->width()) { + length = (this->width() - x); } if (length <= 0) { return; } uint8_t * bufferPtr = buffer; - bufferPtr += (y >> 3) * displayWidth; + bufferPtr += (y >> 3) * this->width(); bufferPtr += x; uint8_t drawBit = 1 << (y & 7); @@ -260,15 +271,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 > displayWidth) return; + if (x < 0 || x >= this->width()) return; if (y < 0) { length += y; y = 0; } - if ( (y + length) > displayHeight) { - length = (displayHeight - y); + if ( (y + length) > this->height()) { + length = (this->height() - y); } if (length <= 0) return; @@ -278,7 +289,7 @@ void OLEDDisplay::drawVerticalLine(int16_t x, int16_t y, int16_t length) { uint8_t drawBit; uint8_t *bufferPtr = buffer; - bufferPtr += (y >> 3) * displayWidth; + bufferPtr += (y >> 3) * this->width(); bufferPtr += x; if (yOffset) { @@ -298,7 +309,7 @@ void OLEDDisplay::drawVerticalLine(int16_t x, int16_t y, int16_t length) { if (length < yOffset) return; length -= yOffset; - bufferPtr += displayWidth; + bufferPtr += this->width(); } if (length >= 8) { @@ -308,14 +319,14 @@ void OLEDDisplay::drawVerticalLine(int16_t x, int16_t y, int16_t length) { drawBit = (color == WHITE) ? 0xFF : 0x00; do { *bufferPtr = drawBit; - bufferPtr += displayWidth; + bufferPtr += this->width(); length -= 8; } while (length >= 8); break; case INVERSE: do { *bufferPtr = ~(*bufferPtr); - bufferPtr += displayWidth; + bufferPtr += this->width(); length -= 8; } while (length >= 8); break; @@ -398,8 +409,8 @@ void OLEDDisplay::drawStringInternal(int16_t xMove, int16_t yMove, char* text, u } // Don't draw anything if it is not on the screen. - if (xMove + textWidth < 0 || xMove > displayWidth ) {return;} - if (yMove + textHeight < 0 || yMove > displayHeight) {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; @@ -552,9 +563,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::resetOrientation() { @@ -621,6 +639,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)); @@ -700,8 +719,7 @@ void OLEDDisplay::sendInitCommands(void) { sendCommand(SETDISPLAYCLOCKDIV); sendCommand(0xF0); // Increase speed of the display max ~96Hz sendCommand(SETMULTIPLEX); - //sendCommand(0x3F); - sendCommand(displayHeight - 1); + sendCommand(this->height() - 1); sendCommand(SETDISPLAYOFFSET); sendCommand(0x00); sendCommand(SETSTARTLINE); @@ -718,7 +736,7 @@ void OLEDDisplay::sendInitCommands(void) { } else if (geometry == GEOMETRY_128_32) { sendCommand(0x02); } - + sendCommand(SETCONTRAST); if (geometry == GEOMETRY_128_64) { @@ -729,6 +747,8 @@ void OLEDDisplay::sendInitCommands(void) { 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 @@ -737,8 +757,8 @@ void OLEDDisplay::sendInitCommands(void) { void inline OLEDDisplay::drawInternal(int16_t xMove, int16_t yMove, int16_t width, int16_t height, const uint8_t *data, uint16_t offset, uint16_t bytesInData) { if (width < 0 || height < 0) return; - if (yMove + height < 0 || yMove > displayHeight) return; - if (xMove + width < 0 || xMove > displayWidth) 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; @@ -760,12 +780,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)) * displayWidth; + int16_t yPos = ((yMove >> 3) + (i % rasterHeight)) * this->width(); +// int16_t yScreenPos = yMove + yOffset; int16_t dataPos = xPos + yPos; if (dataPos >= 0 && dataPos < displayBufferSize && - xPos >= 0 && xPos < displayWidth ) { + xPos >= 0 && xPos < this->width() ) { if (yOffset >= 0) { switch (this->color) { @@ -773,11 +794,12 @@ 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 < (displayBufferSize - displayWidth)) { + + if (dataPos < (displayBufferSize - this->width())) { switch (this->color) { - case WHITE: buffer[dataPos + displayWidth] |= currentByte >> (8 - yOffset); break; - case BLACK: buffer[dataPos + displayWidth] &= ~(currentByte >> (8 - yOffset)); break; - case INVERSE: buffer[dataPos + displayWidth] ^= 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 83c966c..0de5ca0 100644 --- a/OLEDDisplay.h +++ b/OLEDDisplay.h @@ -111,9 +111,15 @@ typedef byte (*FontTableLookupFunction)(const byte ch); class OLEDDisplay : public Print { + private: + const int _width, _height; + public: - virtual ~OLEDDisplay() {} - + virtual ~OLEDDisplay(); + + const int width(void) const { return displayWidth; }; + const int height(void) const { return displayHeight; }; + // Initialize the display bool init(); @@ -211,7 +217,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); // Reset display rotation or mirroring void resetOrientation(); @@ -246,10 +254,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: @@ -276,7 +284,7 @@ class OLEDDisplay : public Print { virtual void sendCommand(uint8_t com) {(void)com;}; // Connect to the display - virtual bool connect() {return false;}; + virtual bool connect() { return false; }; // Send all the init commands void sendInitCommands(); diff --git a/OLEDDisplayUi.cpp b/OLEDDisplayUi.cpp index b29b8b5..85e051b 100644 --- a/OLEDDisplayUi.cpp +++ b/OLEDDisplayUi.cpp @@ -251,32 +251,32 @@ void OLEDDisplayUi::drawFrame(){ switch (this->state.frameState){ case IN_TRANSITION: { float progress = (float) this->state.ticksSinceLastStateSwitch / (float) this->ticksPerTransition; - int16_t x = 0, y = 0, x1 = 0, y1 = 0; + int16_t x = 0, y = 0, x1 = 0, y1 = 0; switch(this->frameAnimationDirection){ case SLIDE_LEFT: - x = -(this->display->getWidth()) * progress; + x = -this->display->width() * progress; y = 0; - x1 = x + this->display->getWidth(); + x1 = x + this->display->width(); y1 = 0; break; case SLIDE_RIGHT: - x = this->display->getWidth() * progress; + x = this->display->width() * progress; y = 0; - x1 = x - this->display->getWidth(); + x1 = x - this->display->width(); y1 = 0; break; case SLIDE_UP: x = 0; - y = -(this->display->getHeight()) * progress; + y = -this->display->height() * progress; x1 = 0; - y1 = y + (this->display->getHeight()); + y1 = y + this->display->height(); break; case SLIDE_DOWN: default: x = 0; - y = (this->display->getHeight()) * progress; + y = this->display->height() * progress; x1 = 0; - y1 = y - (this->display->getHeight()); + y1 = y - this->display->height(); break; } @@ -371,27 +371,28 @@ void OLEDDisplayUi::drawIndicator() { uint16_t frameStartPos = (indicatorSpacing * frameCount / 2); const uint8_t *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 = (this->display->getWidth() / 2) - frameStartPos + indicatorSpacing * i; + x = (this->display->width() / 2) - frameStartPos + 12 * i; break; case BOTTOM: - y = (this->display->getHeight() - 8) + (8 * indicatorFadeProgress); - x = (this->display->getWidth() / 2) - frameStartPos + indicatorSpacing * i; + y = (this->display->height() - 8) + (8 * indicatorFadeProgress); + x = (this->display->width() / 2) - frameStartPos + 12 * i; break; case RIGHT: - x = (this->display->getWidth() - 8) + (8 * indicatorFadeProgress); - y = (this->display->getHeight() / 2) - frameStartPos + indicatorSpacing * i; + x = (this->display->width() - 8) + (8 * indicatorFadeProgress); + y = (this->display->height() / 2) - frameStartPos + 2 + 12 * i; break; case LEFT: default: x = 0 - (8 * indicatorFadeProgress); - y = (this->display->getHeight() / 2) - frameStartPos + indicatorSpacing * i; + y = (this->display->height() / 2) - frameStartPos + 2 + indicatorSpacing * i; break; } diff --git a/SSD1306Wire.h b/SSD1306Wire.h index 674e37e..5884447 100644 --- a/SSD1306Wire.h +++ b/SSD1306Wire.h @@ -68,6 +68,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; @@ -78,9 +79,9 @@ class SSD1306Wire : public OLEDDisplay { // Calculate the Y bounding box of changes // and copy buffer[pos] to buffer_back[pos]; - for (y = 0; y < (displayHeight / 8); y++) { - for (x = 0; x < displayWidth; x++) { - uint16_t pos = x + y * displayWidth; + 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); @@ -95,11 +96,12 @@ 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 == (uint8_t)(~0)) return; sendCommand(COLUMNADDR); - sendCommand(minBoundX); - sendCommand(maxBoundX); + sendCommand(x_offset + minBoundX); + sendCommand(x_offset + maxBoundX); sendCommand(PAGEADDR); sendCommand(minBoundY); @@ -112,7 +114,8 @@ class SSD1306Wire : public OLEDDisplay { Wire.beginTransmission(_address); Wire.write(0x40); } - Wire.write(buffer[x + y * displayWidth]); + + Wire.write(buffer[x + y * this->width()]); k++; if (k == 16) { Wire.endTransmission(); @@ -128,11 +131,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((this->height() / 8) - 1); if (geometry == GEOMETRY_128_64) { sendCommand(0x7);