Newer
Older
/**
* The MIT License (MIT)
*
* Copyright (c) 2016 by Daniel Eichhorn
* Copyright (c) 2016 by Fabrice Weinberg
*
* 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.
*
* Credits for parts of this code go to Mike Rankin. Thank you so much for sharing!
*/
bool OLEDDisplay::init() {
if (!this->connect()) {
DEBUG_OLEDDISPLAY("[OLEDDISPLAY][init] Can't establish connection to display\n");
return false;
}
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");
#ifdef OLEDDISPLAY_DOUBLE_BUFFER
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
#ifdef OLEDDISPLAY_DOUBLE_BUFFER
if (this->buffer_back) free(this->buffer_back);
#endif
void OLEDDisplay::resetDisplay(void) {
#ifdef OLEDDISPLAY_DOUBLE_BUFFER
memset(buffer_back, 1, DISPLAY_BUFFER_SIZE);
void OLEDDisplay::setColor(OLEDDISPLAY_COLOR color) {
void OLEDDisplay::setPixel(int16_t x, int16_t y) {
if (x >= 0 && x < 128 && y >= 0 && y < 64) {
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;
}
}
// Bresenham's algorithm - thx wikipedia and Adafruit_GFX
void OLEDDisplay::drawLine(int16_t x0, int16_t y0, int16_t x1, int16_t y1) {
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
int16_t steep = abs(y1 - y0) > abs(x1 - x0);
if (steep) {
_swap_int16_t(x0, y0);
_swap_int16_t(x1, y1);
}
if (x0 > x1) {
_swap_int16_t(x0, x1);
_swap_int16_t(y0, y1);
}
int16_t dx, dy;
dx = x1 - x0;
dy = abs(y1 - y0);
int16_t err = dx / 2;
int16_t ystep;
if (y0 < y1) {
ystep = 1;
} else {
ystep = -1;
}
for (; x0<=x1; x0++) {
if (steep) {
setPixel(y0, x0);
} else {
setPixel(x0, y0);
}
err -= dy;
if (err < 0) {
y0 += ystep;
err += dx;
}
}
}
void OLEDDisplay::drawRect(int16_t x, int16_t y, int16_t width, int16_t height) {
drawHorizontalLine(x, y, width);
drawVerticalLine(x, y, height);
drawVerticalLine(x + width - 1, y, height);
drawHorizontalLine(x, y + height - 1, width);
void OLEDDisplay::fillRect(int16_t xMove, int16_t yMove, int16_t width, int16_t height) {
for (int16_t x = xMove; x < xMove + width; x++) {
drawVerticalLine(x, yMove, height);
void OLEDDisplay::drawCircle(int16_t x0, int16_t y0, int16_t radius) {
int16_t x = 0, y = radius;
int16_t dp = 1 - radius;
do {
if (dp < 0)
dp = dp + 2 * (++x) + 3;
else
dp = dp + 2 * (++x) - 2 * (--y) + 5;
setPixel(x0 + x, y0 + y); //For the 8 octants
setPixel(x0 - x, y0 + y);
setPixel(x0 + x, y0 - y);
setPixel(x0 - x, y0 - y);
setPixel(x0 + y, y0 + x);
setPixel(x0 - y, y0 + x);
setPixel(x0 + y, y0 - x);
setPixel(x0 - y, y0 - x);
} while (x < y);
setPixel(x0 + radius, y0);
setPixel(x0, y0 + radius);
setPixel(x0 - radius, y0);
setPixel(x0, y0 - radius);
}
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
void OLEDDisplay::drawCircleQuads(int16_t x0, int16_t y0, int16_t radius, uint8_t quads) {
int16_t x = 0, y = radius;
int16_t dp = 1 - radius;
while (x < y) {
if (dp < 0)
dp = dp + 2 * (++x) + 3;
else
dp = dp + 2 * (++x) - 2 * (--y) + 5;
if (quads & 0x1) {
setPixel(x0 + x, y0 - y);
setPixel(x0 + y, y0 - x);
}
if (quads & 0x2) {
setPixel(x0 - y, y0 - x);
setPixel(x0 - x, y0 - y);
}
if (quads & 0x4) {
setPixel(x0 - y, y0 + x);
setPixel(x0 - x, y0 + y);
}
if (quads & 0x8) {
setPixel(x0 + x, y0 + y);
setPixel(x0 + y, y0 + x);
}
}
if (quads & 0x1 && quads & 0x8) {
setPixel(x0 + radius, y0);
}
if (quads & 0x4 && quads & 0x8) {
setPixel(x0, y0 + radius);
}
if (quads & 0x2 && quads & 0x4) {
setPixel(x0 - radius, y0);
}
if (quads & 0x1 && quads & 0x2) {
setPixel(x0, y0 - radius);
}
}
void OLEDDisplay::fillCircle(int16_t x0, int16_t y0, int16_t radius) {
int16_t x = 0, y = radius;
int16_t dp = 1 - radius;
do {
if (dp < 0)
dp = dp + 2 * (++x) + 3;
else
dp = dp + 2 * (++x) - 2 * (--y) + 5;
drawHorizontalLine(x0 - x, y0 - y, 2*x);
drawHorizontalLine(x0 - x, y0 + y, 2*x);
drawHorizontalLine(x0 - y, y0 - x, 2*y);
drawHorizontalLine(x0 - y, y0 + x, 2*y);
} while (x < y);
drawHorizontalLine(x0 - radius, y0, 2 * radius);
void OLEDDisplay::drawHorizontalLine(int16_t x, int16_t y, int16_t length) {
if ( (x + length) > DISPLAY_WIDTH) {
length = (DISPLAY_WIDTH - x);
}
uint8_t * bufferPtr = buffer;
bufferPtr += (y >> 3) * DISPLAY_WIDTH;
bufferPtr += x;
uint8_t drawBit = 1 << (y & 7);
switch (color) {
case WHITE: while (length--) {
*bufferPtr++ |= drawBit;
}; break;
case BLACK: drawBit = ~drawBit; while (length--) {
*bufferPtr++ &= drawBit;
}; break;
case INVERSE: while (length--) {
*bufferPtr++ ^= drawBit;
}; break;
void OLEDDisplay::drawVerticalLine(int16_t x, int16_t y, int16_t length) {
if (y < 0) {
length += y;
y = 0;
}
if ( (y + length) > DISPLAY_HEIGHT) {
length = (DISPLAY_HEIGHT - y);
uint8_t yOffset = y & 7;
uint8_t drawBit;
uint8_t *bufferPtr = buffer;
bufferPtr += (y >> 3) * DISPLAY_WIDTH;
bufferPtr += x;
if (yOffset) {
yOffset = 8 - yOffset;
drawBit = ~(0xFF >> (yOffset));
if (length < yOffset) {
drawBit &= (0xFF >> (yOffset - length));
}
switch (color) {
case WHITE: *bufferPtr |= drawBit; break;
case BLACK: *bufferPtr &= ~drawBit; break;
case INVERSE: *bufferPtr ^= drawBit; break;
length -= yOffset;
bufferPtr += DISPLAY_WIDTH;
}
if (length >= 8) {
switch (color) {
case WHITE:
case BLACK:
drawBit = (color == WHITE) ? 0xFF : 0x00;
do {
*bufferPtr = drawBit;
bufferPtr += DISPLAY_WIDTH;
length -= 8;
} while (length >= 8);
break;
case INVERSE:
do {
*bufferPtr = ~(*bufferPtr);
bufferPtr += DISPLAY_WIDTH;
length -= 8;
} while (length >= 8);
break;
drawBit = (1 << (length & 7)) - 1;
case WHITE: *bufferPtr |= drawBit; break;
case BLACK: *bufferPtr &= ~drawBit; break;
case INVERSE: *bufferPtr ^= drawBit; break;
void OLEDDisplay::drawProgressBar(uint16_t x, uint16_t y, uint16_t width, uint16_t height, uint8_t progress) {
uint16_t radius = height / 2;
uint16_t xRadius = x + radius;
uint16_t yRadius = y + radius;
uint16_t doubleRadius = 2 * radius;
uint16_t innerRadius = radius - 2;
setColor(WHITE);
drawCircleQuads(xRadius, yRadius, radius, 0b00000110);
drawHorizontalLine(xRadius, y, width - doubleRadius + 1);
drawHorizontalLine(xRadius, y + height, width - doubleRadius + 1);
drawCircleQuads(x + width - radius, yRadius, radius, 0b00001001);
uint16_t maxProgressWidth = (width - doubleRadius - 1) * progress / 100;
fillCircle(xRadius, yRadius, innerRadius);
fillRect(xRadius + 1, y + 2, maxProgressWidth, height - 3);
fillCircle(xRadius + maxProgressWidth, yRadius, innerRadius);
void OLEDDisplay::drawFastImage(int16_t xMove, int16_t yMove, int16_t width, int16_t height, const char *image) {
drawInternal(xMove, yMove, width, height, image, 0, 0);
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;
for(int16_t y = 0; y < height; y++) {
for(int16_t x = 0; x < width; x++ ) {
if (x & 7) {
data >>= 1; // Move a bit
} else { // Read new data every 8 bit
data = pgm_read_byte(xbm + (x / 8) + y * widthInXbm);
}
// if there is a bit draw it
if (data & 0x01) {
setPixel(xMove + x, yMove + y);
}
}
}
}
void OLEDDisplay::drawStringInternal(int16_t xMove, int16_t yMove, char* text, uint16_t textLength, uint16_t textWidth) {
uint8_t textHeight = pgm_read_byte(fontData + HEIGHT_POS);
uint8_t firstChar = pgm_read_byte(fontData + FIRST_CHAR_POS);
uint16_t sizeOfJumpTable = pgm_read_byte(fontData + CHAR_NUM_POS) * JUMPTABLE_BYTES;
switch (textAlignment) {
case TEXT_ALIGN_CENTER_BOTH:
yMove -= textHeight >> 1;
// Fallthrough
case TEXT_ALIGN_CENTER:
xMove -= textWidth >> 1; // divide by 2
break;
case TEXT_ALIGN_RIGHT:
xMove -= textWidth;
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;}
for (uint16_t j = 0; j < textLength; j++) {
int16_t xPos = xMove + cursorX;
int16_t yPos = yMove + cursorY;
byte code = text[j];
if (code >= firstChar) {
byte charCode = code - firstChar;
// 4 Bytes per char code
byte msbJumpToChar = pgm_read_byte( fontData + JUMPTABLE_START + charCode * JUMPTABLE_BYTES ); // MSB \ JumpAddress
byte lsbJumpToChar = pgm_read_byte( fontData + JUMPTABLE_START + charCode * JUMPTABLE_BYTES + JUMPTABLE_LSB); // LSB /
byte charByteSize = pgm_read_byte( fontData + JUMPTABLE_START + charCode * JUMPTABLE_BYTES + JUMPTABLE_SIZE); // Size
byte currentCharWidth = pgm_read_byte( fontData + JUMPTABLE_START + charCode * JUMPTABLE_BYTES + JUMPTABLE_WIDTH); // Width
if (!(msbJumpToChar == 255 && lsbJumpToChar == 255)) {
// Get the position of the char data
uint16_t charDataPosition = JUMPTABLE_START + sizeOfJumpTable + ((msbJumpToChar << 8) + lsbJumpToChar);
drawInternal(xPos, yPos, currentCharWidth, textHeight, fontData, charDataPosition, charByteSize);
void OLEDDisplay::drawString(int16_t xMove, int16_t yMove, String strUser) {
uint16_t lineHeight = pgm_read_byte(fontData + HEIGHT_POS);
// char* text must be freed!
char* text = utf8ascii(strUser);
uint16_t yOffset = 0;
// If the string should be centered vertically too
// we need to now how heigh the string is.
if (textAlignment == TEXT_ALIGN_CENTER_BOTH) {
uint16_t lb = 0;
// Find number of linebreaks in text
for (uint16_t i=0;text[i] != 0; i++) {
lb += (text[i] == 10);
}
// Calculate center
yOffset = (lb * lineHeight) / 2;
}
uint16_t line = 0;
char* textPart = strtok(text,"\n");
while (textPart != NULL) {
uint16_t length = strlen(textPart);
drawStringInternal(xMove, yMove - yOffset + (line++) * lineHeight, textPart, length, getStringWidth(textPart, length));
textPart = strtok(NULL, "\n");
}
void OLEDDisplay::drawStringMaxWidth(int16_t xMove, int16_t yMove, uint16_t maxLineWidth, String strUser) {
uint16_t firstChar = pgm_read_byte(fontData + FIRST_CHAR_POS);
uint16_t lineHeight = pgm_read_byte(fontData + HEIGHT_POS);
char* text = utf8ascii(strUser);
uint16_t length = strlen(text);
uint16_t lastDrawnPos = 0;
uint16_t lineNumber = 0;
uint16_t strWidth = 0;
uint16_t preferredBreakpoint = 0;
uint16_t widthAtBreakpoint = 0;
strWidth += pgm_read_byte(fontData + JUMPTABLE_START + (text[i] - firstChar) * JUMPTABLE_BYTES + JUMPTABLE_WIDTH);
// Always try to break on a space or dash
if (text[i] == ' ' || text[i]== '-') {
preferredBreakpoint = i;
widthAtBreakpoint = strWidth;
}
if (strWidth >= maxLineWidth) {
if (preferredBreakpoint == 0) {
preferredBreakpoint = i;
widthAtBreakpoint = strWidth;
}
drawStringInternal(xMove, yMove + (lineNumber++) * lineHeight , &text[lastDrawnPos], preferredBreakpoint - lastDrawnPos, widthAtBreakpoint);
lastDrawnPos = preferredBreakpoint + 1;
// It is possible that we did not draw all letters to i so we need
// to account for the width of the chars from `i - preferredBreakpoint`
// by calculating the width we did not draw yet.
strWidth = strWidth - widthAtBreakpoint;
preferredBreakpoint = 0;
// Draw last part if needed
if (lastDrawnPos < length) {
drawStringInternal(xMove, yMove + lineNumber * lineHeight , &text[lastDrawnPos], length - lastDrawnPos, getStringWidth(&text[lastDrawnPos], length - lastDrawnPos));
uint16_t OLEDDisplay::getStringWidth(const char* text, uint16_t length) {
uint16_t firstChar = pgm_read_byte(fontData + FIRST_CHAR_POS);
uint16_t stringWidth = 0;
uint16_t maxWidth = 0;
while (length--) {
stringWidth += pgm_read_byte(fontData + JUMPTABLE_START + (text[length] - firstChar) * JUMPTABLE_BYTES + JUMPTABLE_WIDTH);
if (text[length] == 10) {
maxWidth = max(maxWidth, stringWidth);
stringWidth = 0;
}
return max(maxWidth, stringWidth);
uint16_t OLEDDisplay::getStringWidth(String strUser) {
char* text = utf8ascii(strUser);
uint16_t length = strlen(text);
uint16_t width = getStringWidth(text, length);
free(text);
return width;
}
void OLEDDisplay::setTextAlignment(OLEDDISPLAY_TEXT_ALIGNMENT textAlignment) {
void OLEDDisplay::setFont(const char *fontData) {
void OLEDDisplay::displayOn(void) {
void OLEDDisplay::displayOff(void) {
void OLEDDisplay::invertDisplay(void) {
void OLEDDisplay::normalDisplay(void) {
void OLEDDisplay::setContrast(char contrast) {
sendCommand(SETCONTRAST);
sendCommand(contrast);
}
void OLEDDisplay::flipScreenVertically() {
sendCommand(SEGREMAP | 0x01);
sendCommand(COMSCANDEC); //Rotate screen 180 Deg
void OLEDDisplay::clear(void) {
void OLEDDisplay::drawLogBuffer(uint16_t xMove, uint16_t yMove) {
uint16_t lineHeight = pgm_read_byte(fontData + HEIGHT_POS);
// Always align left
setTextAlignment(TEXT_ALIGN_LEFT);
// State values
uint16_t length = 0;
uint16_t line = 0;
uint16_t lastPos = 0;
for (uint16_t i=0;i<this->logBufferFilled;i++){
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);
// Draw the remaining string
if (length > 0) {
drawStringInternal(xMove, yMove + line * lineHeight, &this->logBuffer[lastPos], length, 0);
}
}
bool OLEDDisplay::setLogBuffer(uint16_t lines, uint16_t chars){
if (logBuffer != NULL) free(logBuffer);
uint16_t size = lines * chars;
if (size > 0) {
this->logBufferLine = 0; // Lines printed
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));
if(!this->logBuffer) {
DEBUG_OLEDDISPLAY("[OLEDDISPLAY][setLogBuffer] Not enough memory to create log buffer\n");
return false;
}
}
return true;
}
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;
bool maxLineNotReached = this->logBufferLine < this->logBufferMaxLines;
bool bufferNotFull = this->logBufferFilled < this->logBufferSize;
// Can we write to the buffer?
if (bufferNotFull && maxLineNotReached) {
this->logBuffer[logBufferFilled] = utf8ascii(c);
this->logBufferFilled++;
if (c == 10) this->logBufferLine++;
} else {
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
// 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;i<this->logBufferFilled;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
//}
}
// We are always writing all uint8_t to the buffer
return 1;
}
size_t OLEDDisplay::write(const char* str) {
size_t length = strlen(str);
for (size_t i = 0; i < length; i++) {
write(str[i]);
}
void OLEDDisplay::sendInitCommands(void) {
sendCommand(DISPLAYOFF);
sendCommand(SETDISPLAYCLOCKDIV);
sendCommand(0xF0); // Increase speed of the display max ~96Hz
sendCommand(SETMULTIPLEX);
sendCommand(SETDISPLAYOFFSET);
sendCommand(0x00);
sendCommand(CHARGEPUMP);
sendCommand(MEMORYMODE);
sendCommand(0x00);
sendCommand(SEGREMAP);
sendCommand(COMSCANINC);
sendCommand(SETCOMPINS);
sendCommand(0x12);
sendCommand(SETCONTRAST);
sendCommand(0xCF);
sendCommand(SETPRECHARGE);
sendCommand(0xF1);
sendCommand(DISPLAYALLON_RESUME);
sendCommand(NORMALDISPLAY);
sendCommand(DISPLAYON);
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) {
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
if (width < 0 || height < 0) return;
if (yMove + height < 0 || yMove > DISPLAY_HEIGHT) return;
if (xMove + width < 0 || xMove > DISPLAY_WIDTH) return;
uint8_t rasterHeight = 1 + ((height - 1) >> 3); // fast ceil(height / 8.0)
int8_t yOffset = yMove & 7;
bytesInData = bytesInData == 0 ? width * rasterHeight : bytesInData;
int16_t initYMove = yMove;
int8_t initYOffset = yOffset;
for (uint16_t i = 0; i < bytesInData; i++) {
// Reset if next horizontal drawing phase is started.
if ( i % rasterHeight == 0) {
yMove = initYMove;
yOffset = initYOffset;
}
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 yScreenPos = yMove + yOffset;
int16_t dataPos = xPos + yPos;
if (dataPos >= 0 && dataPos < DISPLAY_BUFFER_SIZE &&
xPos >= 0 && xPos < DISPLAY_WIDTH ) {
if (yOffset >= 0) {
switch (this->color) {
case WHITE: buffer[dataPos] |= currentByte << yOffset; break;
case BLACK: buffer[dataPos] &= ~(currentByte << yOffset); break;
case INVERSE: buffer[dataPos] ^= currentByte << yOffset; break;
}
if (dataPos < (DISPLAY_BUFFER_SIZE - DISPLAY_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;
}
}
} else {
// Make new offset position
yOffset = -yOffset;
switch (this->color) {
case WHITE: buffer[dataPos] |= currentByte >> yOffset; break;
case BLACK: buffer[dataPos] &= ~(currentByte >> yOffset); break;
case INVERSE: buffer[dataPos] ^= currentByte >> yOffset; break;
}
// Prepare for next iteration by moving one block up
yMove -= 8;
// and setting the new yOffset
yOffset = 8 - yOffset;
}
yield();
}
}
}
// Code form http://playground.arduino.cc/Main/Utf8ascii
uint8_t OLEDDisplay::utf8ascii(byte ascii) {
static uint8_t LASTCHAR;
if ( ascii < 128 ) { // Standard ASCII-set 0..0x7F handling
LASTCHAR = 0;
return ascii;
}
uint8_t last = LASTCHAR; // get last char
LASTCHAR = ascii;
switch (last) { // conversion depnding on first UTF8-character
case 0xC2: return (ascii); break;
case 0xC3: return (ascii | 0xC0); break;
case 0x82: if (ascii == 0xAC) return (0x80); // special case Euro-symbol
}
return 0; // otherwise: return zero, if character has to be ignored
}
// You need to free the char!
char* OLEDDisplay::utf8ascii(String str) {
uint16_t k = 0;
uint16_t length = str.length() + 1;
// Copy the string into a char array
char* s = (char*) malloc(length * sizeof(char));
if(!s) {
DEBUG_OLEDDISPLAY("[OLEDDISPLAY][utf8ascii] Can't allocate another char array. Drop support for UTF-8.\n");
return (char*) str.c_str();
}
str.toCharArray(s, length);
length--;
for (uint16_t i=0; i < length; i++) {
char c = utf8ascii(s[i]);
if (c!=0) {
s[k++]=c;
}
}
s[k]=0;
// This will leak 's' be sure to free it in the calling function.
return s;
}