Skip to content

Commit 89cc954

Browse files
authored
Merge pull request #4948 from TD-er/cleanup/P036_OLEDframed_checks
[Cleanup] Reduce stack usage + fix bound checks OLED Framed
2 parents 2f1b932 + a3fbe47 commit 89cc954

9 files changed

+505
-472
lines changed

lib/esp8266-oled-ssd1306/OLEDDisplay.cpp

+75-56
Original file line numberDiff line numberDiff line change
@@ -391,9 +391,11 @@ void OLEDDisplay::drawXbm(int16_t xMove, int16_t yMove, int16_t width, int16_t h
391391
}
392392

393393
void OLEDDisplay::drawStringInternal(int16_t xMove, int16_t yMove, char* text, uint16_t textLength, uint16_t textWidth) {
394-
uint8_t textHeight = pgm_read_byte(fontData + HEIGHT_POS);
395-
uint8_t firstChar = pgm_read_byte(fontData + FIRST_CHAR_POS);
396-
uint16_t sizeOfJumpTable = pgm_read_byte(fontData + CHAR_NUM_POS) * JUMPTABLE_BYTES;
394+
if (fontData == nullptr) return;
395+
const uint8_t textHeight = pgm_read_byte(fontData + HEIGHT_POS);
396+
const uint8_t firstChar = pgm_read_byte(fontData + FIRST_CHAR_POS);
397+
const uint8_t numberOfChars = pgm_read_byte(fontData + CHAR_NUM_POS);
398+
const uint16_t sizeOfJumpTable = static_cast<uint16_t>(numberOfChars) * JUMPTABLE_BYTES;
397399

398400
uint8_t cursorX = 0;
399401
uint8_t cursorY = 0;
@@ -417,33 +419,37 @@ void OLEDDisplay::drawStringInternal(int16_t xMove, int16_t yMove, char* text, u
417419
if (yMove + textHeight < 0 || yMove > this->width() ) {return;}
418420

419421
for (uint16_t j = 0; j < textLength; j++) {
420-
int16_t xPos = xMove + cursorX;
421-
int16_t yPos = yMove + cursorY;
422+
const int16_t xPos = xMove + cursorX;
423+
const int16_t yPos = yMove + cursorY;
422424

423-
uint8_t code = text[j];
425+
const uint8_t code = text[j];
424426
if (code >= firstChar) {
425-
uint8_t charCode = code - firstChar;
426-
427-
// 4 Bytes per char code
428-
uint8_t msbJumpToChar = pgm_read_byte( fontData + JUMPTABLE_START + charCode * JUMPTABLE_BYTES ); // MSB \ JumpAddress
429-
uint8_t lsbJumpToChar = pgm_read_byte( fontData + JUMPTABLE_START + charCode * JUMPTABLE_BYTES + JUMPTABLE_LSB); // LSB /
430-
uint8_t charByteSize = pgm_read_byte( fontData + JUMPTABLE_START + charCode * JUMPTABLE_BYTES + JUMPTABLE_SIZE); // Size
431-
uint8_t currentCharWidth = pgm_read_byte( fontData + JUMPTABLE_START + charCode * JUMPTABLE_BYTES + JUMPTABLE_WIDTH); // Width
432-
433-
// Test if the char is drawable
434-
if (!(msbJumpToChar == 255 && lsbJumpToChar == 255)) {
435-
// Get the position of the char data
436-
uint16_t charDataPosition = JUMPTABLE_START + sizeOfJumpTable + ((msbJumpToChar << 8) + lsbJumpToChar);
437-
drawInternal(xPos, yPos, currentCharWidth, textHeight, fontData, charDataPosition, charByteSize);
438-
}
427+
const uint8_t charCode = code - firstChar;
428+
if (charCode < numberOfChars) {
429+
430+
// 4 Bytes per char code
431+
const char* charOffset = fontData + JUMPTABLE_START + charCode * JUMPTABLE_BYTES;
432+
const uint8_t msbJumpToChar = pgm_read_byte( charOffset ); // MSB \ JumpAddress
433+
const uint8_t lsbJumpToChar = pgm_read_byte( charOffset + JUMPTABLE_LSB); // LSB /
434+
const uint8_t charByteSize = pgm_read_byte( charOffset + JUMPTABLE_SIZE); // Size
435+
const uint8_t currentCharWidth = pgm_read_byte( charOffset + JUMPTABLE_WIDTH); // Width
436+
437+
// Test if the char is drawable
438+
if (!(msbJumpToChar == 255 && lsbJumpToChar == 255)) {
439+
// Get the position of the char data
440+
uint16_t charDataPosition = JUMPTABLE_START + sizeOfJumpTable + ((msbJumpToChar << 8) + lsbJumpToChar);
441+
drawInternal(xPos, yPos, currentCharWidth, textHeight, fontData, charDataPosition, charByteSize);
442+
}
439443

440-
cursorX += currentCharWidth;
444+
cursorX += currentCharWidth;
445+
}
441446
}
442447
}
443448
}
444449

445450

446451
void OLEDDisplay::drawString(int16_t xMove, int16_t yMove, const String& strUser) {
452+
if (fontData == nullptr) return;
447453
uint16_t lineHeight = pgm_read_byte(fontData + HEIGHT_POS);
448454

449455
// char* text must be freed!
@@ -473,6 +479,7 @@ void OLEDDisplay::drawString(int16_t xMove, int16_t yMove, const String& strUser
473479
}
474480

475481
void OLEDDisplay::drawStringMaxWidth(int16_t xMove, int16_t yMove, uint16_t maxLineWidth, const String& strUser) {
482+
if (fontData == nullptr) return;
476483
uint16_t firstChar = pgm_read_byte(fontData + FIRST_CHAR_POS);
477484
uint16_t lineHeight = pgm_read_byte(fontData + HEIGHT_POS);
478485

@@ -519,6 +526,7 @@ void OLEDDisplay::drawStringMaxWidth(int16_t xMove, int16_t yMove, uint16_t maxL
519526
}
520527

521528
uint16_t OLEDDisplay::getStringWidth(const char* text, uint16_t length) {
529+
if (fontData == nullptr) return 0;
522530
uint16_t firstChar = pgm_read_byte(fontData + FIRST_CHAR_POS);
523531

524532
uint16_t stringWidth = 0;
@@ -544,6 +552,7 @@ uint16_t OLEDDisplay::getStringWidth(const String& strUser) {
544552
}
545553

546554
uint8_t OLEDDisplay::getCharWidth(const char c) {
555+
if (fontData == nullptr) return 0;
547556
uint8_t firstChar = pgm_read_byte(fontData + FIRST_CHAR_POS);
548557
if (utf8ascii(c) == 0)
549558
return 0;
@@ -577,15 +586,20 @@ void OLEDDisplay::normalDisplay(void) {
577586
}
578587

579588
void OLEDDisplay::setContrast(char contrast, char precharge, char comdetect) {
580-
sendCommand(SETPRECHARGE); //0xD9
581-
sendCommand(precharge); //0xF1 default, to lower the contrast, put 1-1F
582-
sendCommand(SETCONTRAST);
583-
sendCommand(contrast); // 0-255
584-
sendCommand(SETVCOMDETECT); //0xDB, (additionally needed to lower the contrast)
585-
sendCommand(comdetect); //0x40 default, to lower the contrast, put 0
586-
sendCommand(DISPLAYALLON_RESUME);
587-
sendCommand(NORMALDISPLAY);
588-
sendCommand(DISPLAYON);
589+
const uint8_t commands[] = {
590+
SETPRECHARGE, //0xD9
591+
precharge, //0xF1 default, to lower the contrast, put 1-1F
592+
SETCONTRAST,
593+
contrast, // 0-255
594+
SETVCOMDETECT, //0xDB, (additionally needed to lower the contrast)
595+
comdetect, //0x40 default, to lower the contrast, put 0
596+
DISPLAYALLON_RESUME,
597+
NORMALDISPLAY,
598+
DISPLAYON
599+
};
600+
for (uint8_t i = 0; i < sizeof(commands); ++i) {
601+
sendCommand(commands[i]);
602+
}
589603
}
590604

591605
void OLEDDisplay::flipScreenVertically() {
@@ -598,6 +612,7 @@ void OLEDDisplay::clear(void) {
598612
}
599613

600614
void OLEDDisplay::drawLogBuffer(uint16_t xMove, uint16_t yMove) {
615+
if (fontData == nullptr) return;
601616
uint16_t lineHeight = pgm_read_byte(fontData + HEIGHT_POS);
602617
// Always align left
603618
setTextAlignment(TEXT_ALIGN_LEFT);
@@ -770,32 +785,36 @@ void OLEDDisplay::SetComPins(uint8_t _compins) {
770785

771786
// Private functions
772787
void OLEDDisplay::sendInitCommands(void) {
773-
sendCommand(DISPLAYOFF);
774-
sendCommand(SETDISPLAYCLOCKDIV);
775-
sendCommand(0xF0); // Increase speed of the display max ~96Hz
776-
sendCommand(SETMULTIPLEX);
777-
sendCommand(this->height() - 1);
778-
sendCommand(SETDISPLAYOFFSET);
779-
sendCommand(0x00);
780-
sendCommand(SETSTARTLINE);
781-
sendCommand(CHARGEPUMP);
782-
sendCommand(0x14);
783-
sendCommand(MEMORYMODE);
784-
sendCommand(0x00);
785-
sendCommand(SEGREMAP);
786-
sendCommand(COMSCANINC);
787-
sendCommand(SETCOMPINS);
788-
sendCommand(0x12); // according to the adafruit lib, sometimes this may need to be 0x02
789-
sendCommand(SETCONTRAST);
790-
sendCommand(0xCF);
791-
sendCommand(SETPRECHARGE);
792-
sendCommand(0xF1);
793-
sendCommand(SETVCOMDETECT); //0xDB, (additionally needed to lower the contrast)
794-
sendCommand(0x40); //0x40 default, to lower the contrast, put 0
795-
sendCommand(DISPLAYALLON_RESUME);
796-
sendCommand(NORMALDISPLAY);
797-
sendCommand(0x2e); // stop scroll
798-
sendCommand(DISPLAYON);
788+
const uint8_t commands[] = {
789+
DISPLAYOFF,
790+
SETDISPLAYCLOCKDIV,
791+
0xF0, // Increase speed of the display max ~96Hz
792+
SETMULTIPLEX,
793+
static_cast<uint8_t>(this->height() - 1), // FIXME TD-er: should add some checks here?
794+
SETDISPLAYOFFSET,
795+
0x00,
796+
SETSTARTLINE,
797+
CHARGEPUMP,
798+
0x14,
799+
MEMORYMODE,
800+
0x00,
801+
SEGREMAP,
802+
COMSCANINC,
803+
SETCOMPINS,
804+
0x12, // according to the adafruit lib, sometimes this may need to be 0x02
805+
SETCONTRAST,
806+
0xCF,
807+
SETPRECHARGE,
808+
0xF1,
809+
SETVCOMDETECT, //0xDB, (additionally needed to lower the contrast)
810+
0x40, //0x40 default, to lower the contrast, put 0
811+
DISPLAYALLON_RESUME,
812+
NORMALDISPLAY,
813+
0x2e, // stop scroll
814+
DISPLAYON};
815+
for (uint8_t i = 0; i < sizeof(commands); ++i) {
816+
sendCommand(commands[i]);
817+
}
799818
}
800819

801820
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) {
+76
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
#include "SH1106Wire.h"
2+
3+
4+
5+
SH1106Wire::SH1106Wire(uint8_t address, uint8_t sda, uint8_t scl) :
6+
_address(address),
7+
_sda(sda),
8+
_scl(scl) {}
9+
10+
bool SH1106Wire::connect() {
11+
Wire.begin(this->_sda, this->_scl);
12+
return true;
13+
}
14+
15+
void SH1106Wire::display(void) {
16+
#ifdef OLEDDISPLAY_DOUBLE_BUFFER
17+
uint8_t minBoundX, minBoundY, maxBoundX, maxBoundY;
18+
if (!getChangedBoundingBox(minBoundX, minBoundY, maxBoundX, maxBoundY))
19+
return;
20+
21+
22+
// Calculate the colum offset
23+
uint8_t minBoundXp2H = (minBoundX + 2) & 0x0F;
24+
uint8_t minBoundXp2L = 0x10 | ((minBoundX + 2) >> 4 );
25+
26+
uint8_t k = 0;
27+
for (uint8_t y = minBoundY; y <= maxBoundY; y++) {
28+
sendCommand(0xB0 + y);
29+
sendCommand(minBoundXp2H);
30+
sendCommand(minBoundXp2L);
31+
for (uint8_t x = minBoundX; x <= maxBoundX; x++) {
32+
if (k == 0) {
33+
Wire.beginTransmission(_address);
34+
Wire.write(0x40);
35+
}
36+
Wire.write(buffer[x + y * DISPLAY_WIDTH]);
37+
k++;
38+
if (k == 16) {
39+
Wire.endTransmission();
40+
k = 0;
41+
}
42+
}
43+
if (k != 0) {
44+
Wire.endTransmission();
45+
k = 0;
46+
}
47+
yield();
48+
}
49+
50+
if (k != 0) {
51+
Wire.endTransmission();
52+
}
53+
#else
54+
uint8_t * p = &buffer[0];
55+
for (uint8_t y=0; y<8; y++) {
56+
sendCommand(0xB0+y);
57+
sendCommand(0x02);
58+
sendCommand(0x10);
59+
for( uint8_t x=0; x<8; x++) {
60+
Wire.beginTransmission(_address);
61+
Wire.write(0x40);
62+
for (uint8_t k = 0; k < 16; k++) {
63+
Wire.write(*p++);
64+
}
65+
Wire.endTransmission();
66+
}
67+
}
68+
#endif
69+
}
70+
71+
void SH1106Wire::sendCommand(uint8_t command) {
72+
Wire.beginTransmission(_address);
73+
Wire.write(0x80);
74+
Wire.write(command);
75+
Wire.endTransmission();
76+
}

lib/esp8266-oled-ssd1306/SH1106Wire.h

+4-70
Original file line numberDiff line numberDiff line change
@@ -44,80 +44,14 @@ class SH1106Wire : public OLEDDisplay {
4444
uint8_t _scl;
4545

4646
public:
47-
SH1106Wire(uint8_t _address, uint8_t _sda, uint8_t _scl) {
48-
this->_address = _address;
49-
this->_sda = _sda;
50-
this->_scl = _scl;
51-
}
47+
SH1106Wire(uint8_t _address, uint8_t _sda, uint8_t _scl);
5248

53-
bool connect() {
54-
Wire.begin(this->_sda, this->_scl);
55-
return true;
56-
}
49+
bool connect() override;
5750

58-
void display(void) {
59-
#ifdef OLEDDISPLAY_DOUBLE_BUFFER
60-
uint8_t minBoundX, minBoundY, maxBoundX, maxBoundY;
61-
if (!getChangedBoundingBox(minBoundX, minBoundY, maxBoundX, maxBoundY))
62-
return;
63-
64-
65-
// Calculate the colum offset
66-
uint8_t minBoundXp2H = (minBoundX + 2) & 0x0F;
67-
uint8_t minBoundXp2L = 0x10 | ((minBoundX + 2) >> 4 );
68-
69-
uint8_t k = 0;
70-
for (uint8_t y = minBoundY; y <= maxBoundY; y++) {
71-
sendCommand(0xB0 + y);
72-
sendCommand(minBoundXp2H);
73-
sendCommand(minBoundXp2L);
74-
for (uint8_t x = minBoundX; x <= maxBoundX; x++) {
75-
if (k == 0) {
76-
Wire.beginTransmission(_address);
77-
Wire.write(0x40);
78-
}
79-
Wire.write(buffer[x + y * DISPLAY_WIDTH]);
80-
k++;
81-
if (k == 16) {
82-
Wire.endTransmission();
83-
k = 0;
84-
}
85-
}
86-
if (k != 0) {
87-
Wire.endTransmission();
88-
k = 0;
89-
}
90-
yield();
91-
}
92-
93-
if (k != 0) {
94-
Wire.endTransmission();
95-
}
96-
#else
97-
uint8_t * p = &buffer[0];
98-
for (uint8_t y=0; y<8; y++) {
99-
sendCommand(0xB0+y);
100-
sendCommand(0x02);
101-
sendCommand(0x10);
102-
for( uint8_t x=0; x<8; x++) {
103-
Wire.beginTransmission(_address);
104-
Wire.write(0x40);
105-
for (uint8_t k = 0; k < 16; k++) {
106-
Wire.write(*p++);
107-
}
108-
Wire.endTransmission();
109-
}
110-
}
111-
#endif
112-
}
51+
void display(void) override;
11352

11453
private:
115-
inline void sendCommand(uint8_t command) __attribute__((always_inline)){
116-
Wire.beginTransmission(_address);
117-
Wire.write(0x80);
118-
Wire.write(command);
119-
Wire.endTransmission();
120-
}
54+
void sendCommand(uint8_t command) override;
12155

12256

12357
};

0 commit comments

Comments
 (0)