ThingPulse OLED SSD1306

Dependents:   Turtle_RadioShuttle

Committer:
Helmut64
Date:
Wed Apr 10 14:15:31 2019 +0000
Revision:
0:56dd5df33ab4
Child:
1:9270c15c6aea
initial mbed library

Who changed what in which revision?

UserRevisionLine numberNew contents of line
Helmut64 0:56dd5df33ab4 1 /**
Helmut64 0:56dd5df33ab4 2 * The MIT License (MIT)
Helmut64 0:56dd5df33ab4 3 *
Helmut64 0:56dd5df33ab4 4 * Copyright (c) 2018 by ThingPulse, Daniel Eichhorn
Helmut64 0:56dd5df33ab4 5 * Copyright (c) 2018 by Fabrice Weinberg
Helmut64 0:56dd5df33ab4 6 * Copyright (c) 2019 by Helmut Tschemernjak - www.radioshuttle.de
Helmut64 0:56dd5df33ab4 7 *
Helmut64 0:56dd5df33ab4 8 * Permission is hereby granted, free of charge, to any person obtaining a copy
Helmut64 0:56dd5df33ab4 9 * of this software and associated documentation files (the "Software"), to deal
Helmut64 0:56dd5df33ab4 10 * in the Software without restriction, including without limitation the rights
Helmut64 0:56dd5df33ab4 11 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
Helmut64 0:56dd5df33ab4 12 * copies of the Software, and to permit persons to whom the Software is
Helmut64 0:56dd5df33ab4 13 * furnished to do so, subject to the following conditions:
Helmut64 0:56dd5df33ab4 14 *
Helmut64 0:56dd5df33ab4 15 * The above copyright notice and this permission notice shall be included in all
Helmut64 0:56dd5df33ab4 16 * copies or substantial portions of the Software.
Helmut64 0:56dd5df33ab4 17 *
Helmut64 0:56dd5df33ab4 18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
Helmut64 0:56dd5df33ab4 19 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
Helmut64 0:56dd5df33ab4 20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
Helmut64 0:56dd5df33ab4 21 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
Helmut64 0:56dd5df33ab4 22 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
Helmut64 0:56dd5df33ab4 23 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
Helmut64 0:56dd5df33ab4 24 * SOFTWARE.
Helmut64 0:56dd5df33ab4 25 *
Helmut64 0:56dd5df33ab4 26 * ThingPulse invests considerable time and money to develop these open source libraries.
Helmut64 0:56dd5df33ab4 27 * Please support us by buying our products (and not the clones) from
Helmut64 0:56dd5df33ab4 28 * https://thingpulse.com
Helmut64 0:56dd5df33ab4 29 *
Helmut64 0:56dd5df33ab4 30 */
Helmut64 0:56dd5df33ab4 31
Helmut64 0:56dd5df33ab4 32 /*
Helmut64 0:56dd5df33ab4 33 * TODO Helmut
Helmut64 0:56dd5df33ab4 34 * - test/finish dislplay.printf() on mbed-os
Helmut64 0:56dd5df33ab4 35 * - Finish _putc with drawLogBuffer when running display
Helmut64 0:56dd5df33ab4 36 * - Fix problem that the x is larger than 0 (somehow shifted display) on single buffer
Helmut64 0:56dd5df33ab4 37 */
Helmut64 0:56dd5df33ab4 38
Helmut64 0:56dd5df33ab4 39 #include "OLEDDisplay.h"
Helmut64 0:56dd5df33ab4 40
Helmut64 0:56dd5df33ab4 41 OLEDDisplay::OLEDDisplay() {
Helmut64 0:56dd5df33ab4 42
Helmut64 0:56dd5df33ab4 43 displayWidth = 128;
Helmut64 0:56dd5df33ab4 44 displayHeight = 64;
Helmut64 0:56dd5df33ab4 45 displayBufferSize = 1024;
Helmut64 0:56dd5df33ab4 46 color = WHITE;
Helmut64 0:56dd5df33ab4 47 geometry = GEOMETRY_128_64;
Helmut64 0:56dd5df33ab4 48 textAlignment = TEXT_ALIGN_LEFT;
Helmut64 0:56dd5df33ab4 49 fontData = ArialMT_Plain_10;
Helmut64 0:56dd5df33ab4 50 fontTableLookupFunction = DefaultFontTableLookup;
Helmut64 0:56dd5df33ab4 51 buffer = NULL;
Helmut64 0:56dd5df33ab4 52 buffer_back = NULL;
Helmut64 0:56dd5df33ab4 53 }
Helmut64 0:56dd5df33ab4 54
Helmut64 0:56dd5df33ab4 55 OLEDDisplay::~OLEDDisplay() {
Helmut64 0:56dd5df33ab4 56 end();
Helmut64 0:56dd5df33ab4 57 }
Helmut64 0:56dd5df33ab4 58
Helmut64 0:56dd5df33ab4 59 bool OLEDDisplay::init() {
Helmut64 0:56dd5df33ab4 60
Helmut64 0:56dd5df33ab4 61 logBufferSize = 0;
Helmut64 0:56dd5df33ab4 62 logBufferFilled = 0;
Helmut64 0:56dd5df33ab4 63 logBufferLine = 0;
Helmut64 0:56dd5df33ab4 64 logBufferMaxLines = 0;
Helmut64 0:56dd5df33ab4 65 logBuffer = NULL;
Helmut64 0:56dd5df33ab4 66
Helmut64 0:56dd5df33ab4 67 if (!this->connect()) {
Helmut64 0:56dd5df33ab4 68 DEBUG_OLEDDISPLAY("[OLEDDISPLAY][init] Can't establish connection to display\n");
Helmut64 0:56dd5df33ab4 69 return false;
Helmut64 0:56dd5df33ab4 70 }
Helmut64 0:56dd5df33ab4 71
Helmut64 0:56dd5df33ab4 72 if(this->buffer==NULL) {
Helmut64 0:56dd5df33ab4 73 this->buffer = (uint8_t*) malloc((sizeof(uint8_t) * displayBufferSize) + getBufferOffset());
Helmut64 0:56dd5df33ab4 74 this->buffer += getBufferOffset();
Helmut64 0:56dd5df33ab4 75
Helmut64 0:56dd5df33ab4 76 if(!this->buffer) {
Helmut64 0:56dd5df33ab4 77 DEBUG_OLEDDISPLAY("[OLEDDISPLAY][init] Not enough memory to create display\n");
Helmut64 0:56dd5df33ab4 78 return false;
Helmut64 0:56dd5df33ab4 79 }
Helmut64 0:56dd5df33ab4 80 }
Helmut64 0:56dd5df33ab4 81
Helmut64 0:56dd5df33ab4 82 #ifdef OLEDDISPLAY_DOUBLE_BUFFER
Helmut64 0:56dd5df33ab4 83 if(this->buffer_back==NULL) {
Helmut64 0:56dd5df33ab4 84 this->buffer_back = (uint8_t*) malloc((sizeof(uint8_t) * displayBufferSize) + getBufferOffset());
Helmut64 0:56dd5df33ab4 85 this->buffer_back += getBufferOffset();
Helmut64 0:56dd5df33ab4 86
Helmut64 0:56dd5df33ab4 87 if(!this->buffer_back) {
Helmut64 0:56dd5df33ab4 88 DEBUG_OLEDDISPLAY("[OLEDDISPLAY][init] Not enough memory to create back buffer\n");
Helmut64 0:56dd5df33ab4 89 free(this->buffer - getBufferOffset());
Helmut64 0:56dd5df33ab4 90 return false;
Helmut64 0:56dd5df33ab4 91 }
Helmut64 0:56dd5df33ab4 92 }
Helmut64 0:56dd5df33ab4 93 #endif
Helmut64 0:56dd5df33ab4 94
Helmut64 0:56dd5df33ab4 95 sendInitCommands();
Helmut64 0:56dd5df33ab4 96 resetDisplay();
Helmut64 0:56dd5df33ab4 97
Helmut64 0:56dd5df33ab4 98 return true;
Helmut64 0:56dd5df33ab4 99 }
Helmut64 0:56dd5df33ab4 100
Helmut64 0:56dd5df33ab4 101 void OLEDDisplay::end() {
Helmut64 0:56dd5df33ab4 102 if (this->buffer) { free(this->buffer - getBufferOffset()); this->buffer = NULL; }
Helmut64 0:56dd5df33ab4 103 #ifdef OLEDDISPLAY_DOUBLE_BUFFER
Helmut64 0:56dd5df33ab4 104 if (this->buffer_back) { free(this->buffer_back - getBufferOffset()); this->buffer_back = NULL; }
Helmut64 0:56dd5df33ab4 105 #endif
Helmut64 0:56dd5df33ab4 106 if (this->logBuffer != NULL) { free(this->logBuffer); this->logBuffer = NULL; }
Helmut64 0:56dd5df33ab4 107 }
Helmut64 0:56dd5df33ab4 108
Helmut64 0:56dd5df33ab4 109 void OLEDDisplay::resetDisplay(void) {
Helmut64 0:56dd5df33ab4 110 clear();
Helmut64 0:56dd5df33ab4 111 #ifdef OLEDDISPLAY_DOUBLE_BUFFER
Helmut64 0:56dd5df33ab4 112 memset(buffer_back, 1, displayBufferSize);
Helmut64 0:56dd5df33ab4 113 #endif
Helmut64 0:56dd5df33ab4 114 display();
Helmut64 0:56dd5df33ab4 115 }
Helmut64 0:56dd5df33ab4 116
Helmut64 0:56dd5df33ab4 117 void OLEDDisplay::setColor(OLEDDISPLAY_COLOR color) {
Helmut64 0:56dd5df33ab4 118 this->color = color;
Helmut64 0:56dd5df33ab4 119 }
Helmut64 0:56dd5df33ab4 120
Helmut64 0:56dd5df33ab4 121 OLEDDISPLAY_COLOR OLEDDisplay::getColor() {
Helmut64 0:56dd5df33ab4 122 return this->color;
Helmut64 0:56dd5df33ab4 123 }
Helmut64 0:56dd5df33ab4 124
Helmut64 0:56dd5df33ab4 125 void OLEDDisplay::setPixel(int16_t x, int16_t y) {
Helmut64 0:56dd5df33ab4 126 if (x >= 0 && x < this->width() && y >= 0 && y < this->height()) {
Helmut64 0:56dd5df33ab4 127 switch (color) {
Helmut64 0:56dd5df33ab4 128 case WHITE: buffer[x + (y / 8) * this->width()] |= (1 << (y & 7)); break;
Helmut64 0:56dd5df33ab4 129 case BLACK: buffer[x + (y / 8) * this->width()] &= ~(1 << (y & 7)); break;
Helmut64 0:56dd5df33ab4 130 case INVERSE: buffer[x + (y / 8) * this->width()] ^= (1 << (y & 7)); break;
Helmut64 0:56dd5df33ab4 131 }
Helmut64 0:56dd5df33ab4 132 }
Helmut64 0:56dd5df33ab4 133 }
Helmut64 0:56dd5df33ab4 134
Helmut64 0:56dd5df33ab4 135 // Bresenham's algorithm - thx wikipedia and Adafruit_GFX
Helmut64 0:56dd5df33ab4 136 void OLEDDisplay::drawLine(int16_t x0, int16_t y0, int16_t x1, int16_t y1) {
Helmut64 0:56dd5df33ab4 137 int16_t steep = abs(y1 - y0) > abs(x1 - x0);
Helmut64 0:56dd5df33ab4 138 if (steep) {
Helmut64 0:56dd5df33ab4 139 _swap_int16_t(x0, y0);
Helmut64 0:56dd5df33ab4 140 _swap_int16_t(x1, y1);
Helmut64 0:56dd5df33ab4 141 }
Helmut64 0:56dd5df33ab4 142
Helmut64 0:56dd5df33ab4 143 if (x0 > x1) {
Helmut64 0:56dd5df33ab4 144 _swap_int16_t(x0, x1);
Helmut64 0:56dd5df33ab4 145 _swap_int16_t(y0, y1);
Helmut64 0:56dd5df33ab4 146 }
Helmut64 0:56dd5df33ab4 147
Helmut64 0:56dd5df33ab4 148 int16_t dx, dy;
Helmut64 0:56dd5df33ab4 149 dx = x1 - x0;
Helmut64 0:56dd5df33ab4 150 dy = abs(y1 - y0);
Helmut64 0:56dd5df33ab4 151
Helmut64 0:56dd5df33ab4 152 int16_t err = dx / 2;
Helmut64 0:56dd5df33ab4 153 int16_t ystep;
Helmut64 0:56dd5df33ab4 154
Helmut64 0:56dd5df33ab4 155 if (y0 < y1) {
Helmut64 0:56dd5df33ab4 156 ystep = 1;
Helmut64 0:56dd5df33ab4 157 } else {
Helmut64 0:56dd5df33ab4 158 ystep = -1;
Helmut64 0:56dd5df33ab4 159 }
Helmut64 0:56dd5df33ab4 160
Helmut64 0:56dd5df33ab4 161 for (; x0<=x1; x0++) {
Helmut64 0:56dd5df33ab4 162 if (steep) {
Helmut64 0:56dd5df33ab4 163 setPixel(y0, x0);
Helmut64 0:56dd5df33ab4 164 } else {
Helmut64 0:56dd5df33ab4 165 setPixel(x0, y0);
Helmut64 0:56dd5df33ab4 166 }
Helmut64 0:56dd5df33ab4 167 err -= dy;
Helmut64 0:56dd5df33ab4 168 if (err < 0) {
Helmut64 0:56dd5df33ab4 169 y0 += ystep;
Helmut64 0:56dd5df33ab4 170 err += dx;
Helmut64 0:56dd5df33ab4 171 }
Helmut64 0:56dd5df33ab4 172 }
Helmut64 0:56dd5df33ab4 173 }
Helmut64 0:56dd5df33ab4 174
Helmut64 0:56dd5df33ab4 175 void OLEDDisplay::drawRect(int16_t x, int16_t y, int16_t width, int16_t height) {
Helmut64 0:56dd5df33ab4 176 drawHorizontalLine(x, y, width);
Helmut64 0:56dd5df33ab4 177 drawVerticalLine(x, y, height);
Helmut64 0:56dd5df33ab4 178 drawVerticalLine(x + width - 1, y, height);
Helmut64 0:56dd5df33ab4 179 drawHorizontalLine(x, y + height - 1, width);
Helmut64 0:56dd5df33ab4 180 }
Helmut64 0:56dd5df33ab4 181
Helmut64 0:56dd5df33ab4 182 void OLEDDisplay::fillRect(int16_t xMove, int16_t yMove, int16_t width, int16_t height) {
Helmut64 0:56dd5df33ab4 183 for (int16_t x = xMove; x < xMove + width; x++) {
Helmut64 0:56dd5df33ab4 184 drawVerticalLine(x, yMove, height);
Helmut64 0:56dd5df33ab4 185 }
Helmut64 0:56dd5df33ab4 186 }
Helmut64 0:56dd5df33ab4 187
Helmut64 0:56dd5df33ab4 188 void OLEDDisplay::drawCircle(int16_t x0, int16_t y0, int16_t radius) {
Helmut64 0:56dd5df33ab4 189 int16_t x = 0, y = radius;
Helmut64 0:56dd5df33ab4 190 int16_t dp = 1 - radius;
Helmut64 0:56dd5df33ab4 191 do {
Helmut64 0:56dd5df33ab4 192 if (dp < 0)
Helmut64 0:56dd5df33ab4 193 dp = dp + 2 * (x++) + 3;
Helmut64 0:56dd5df33ab4 194 else
Helmut64 0:56dd5df33ab4 195 dp = dp + 2 * (x++) - 2 * (y--) + 5;
Helmut64 0:56dd5df33ab4 196
Helmut64 0:56dd5df33ab4 197 setPixel(x0 + x, y0 + y); //For the 8 octants
Helmut64 0:56dd5df33ab4 198 setPixel(x0 - x, y0 + y);
Helmut64 0:56dd5df33ab4 199 setPixel(x0 + x, y0 - y);
Helmut64 0:56dd5df33ab4 200 setPixel(x0 - x, y0 - y);
Helmut64 0:56dd5df33ab4 201 setPixel(x0 + y, y0 + x);
Helmut64 0:56dd5df33ab4 202 setPixel(x0 - y, y0 + x);
Helmut64 0:56dd5df33ab4 203 setPixel(x0 + y, y0 - x);
Helmut64 0:56dd5df33ab4 204 setPixel(x0 - y, y0 - x);
Helmut64 0:56dd5df33ab4 205
Helmut64 0:56dd5df33ab4 206 } while (x < y);
Helmut64 0:56dd5df33ab4 207
Helmut64 0:56dd5df33ab4 208 setPixel(x0 + radius, y0);
Helmut64 0:56dd5df33ab4 209 setPixel(x0, y0 + radius);
Helmut64 0:56dd5df33ab4 210 setPixel(x0 - radius, y0);
Helmut64 0:56dd5df33ab4 211 setPixel(x0, y0 - radius);
Helmut64 0:56dd5df33ab4 212 }
Helmut64 0:56dd5df33ab4 213
Helmut64 0:56dd5df33ab4 214 void OLEDDisplay::drawCircleQuads(int16_t x0, int16_t y0, int16_t radius, uint8_t quads) {
Helmut64 0:56dd5df33ab4 215 int16_t x = 0, y = radius;
Helmut64 0:56dd5df33ab4 216 int16_t dp = 1 - radius;
Helmut64 0:56dd5df33ab4 217 while (x < y) {
Helmut64 0:56dd5df33ab4 218 if (dp < 0)
Helmut64 0:56dd5df33ab4 219 dp = dp + 2 * (x++) + 3;
Helmut64 0:56dd5df33ab4 220 else
Helmut64 0:56dd5df33ab4 221 dp = dp + 2 * (x++) - 2 * (y--) + 5;
Helmut64 0:56dd5df33ab4 222 if (quads & 0x1) {
Helmut64 0:56dd5df33ab4 223 setPixel(x0 + x, y0 - y);
Helmut64 0:56dd5df33ab4 224 setPixel(x0 + y, y0 - x);
Helmut64 0:56dd5df33ab4 225 }
Helmut64 0:56dd5df33ab4 226 if (quads & 0x2) {
Helmut64 0:56dd5df33ab4 227 setPixel(x0 - y, y0 - x);
Helmut64 0:56dd5df33ab4 228 setPixel(x0 - x, y0 - y);
Helmut64 0:56dd5df33ab4 229 }
Helmut64 0:56dd5df33ab4 230 if (quads & 0x4) {
Helmut64 0:56dd5df33ab4 231 setPixel(x0 - y, y0 + x);
Helmut64 0:56dd5df33ab4 232 setPixel(x0 - x, y0 + y);
Helmut64 0:56dd5df33ab4 233 }
Helmut64 0:56dd5df33ab4 234 if (quads & 0x8) {
Helmut64 0:56dd5df33ab4 235 setPixel(x0 + x, y0 + y);
Helmut64 0:56dd5df33ab4 236 setPixel(x0 + y, y0 + x);
Helmut64 0:56dd5df33ab4 237 }
Helmut64 0:56dd5df33ab4 238 }
Helmut64 0:56dd5df33ab4 239 if (quads & 0x1 && quads & 0x8) {
Helmut64 0:56dd5df33ab4 240 setPixel(x0 + radius, y0);
Helmut64 0:56dd5df33ab4 241 }
Helmut64 0:56dd5df33ab4 242 if (quads & 0x4 && quads & 0x8) {
Helmut64 0:56dd5df33ab4 243 setPixel(x0, y0 + radius);
Helmut64 0:56dd5df33ab4 244 }
Helmut64 0:56dd5df33ab4 245 if (quads & 0x2 && quads & 0x4) {
Helmut64 0:56dd5df33ab4 246 setPixel(x0 - radius, y0);
Helmut64 0:56dd5df33ab4 247 }
Helmut64 0:56dd5df33ab4 248 if (quads & 0x1 && quads & 0x2) {
Helmut64 0:56dd5df33ab4 249 setPixel(x0, y0 - radius);
Helmut64 0:56dd5df33ab4 250 }
Helmut64 0:56dd5df33ab4 251 }
Helmut64 0:56dd5df33ab4 252
Helmut64 0:56dd5df33ab4 253
Helmut64 0:56dd5df33ab4 254 void OLEDDisplay::fillCircle(int16_t x0, int16_t y0, int16_t radius) {
Helmut64 0:56dd5df33ab4 255 int16_t x = 0, y = radius;
Helmut64 0:56dd5df33ab4 256 int16_t dp = 1 - radius;
Helmut64 0:56dd5df33ab4 257 do {
Helmut64 0:56dd5df33ab4 258 if (dp < 0)
Helmut64 0:56dd5df33ab4 259 dp = dp + 2 * (x++) + 3;
Helmut64 0:56dd5df33ab4 260 else
Helmut64 0:56dd5df33ab4 261 dp = dp + 2 * (x++) - 2 * (y--) + 5;
Helmut64 0:56dd5df33ab4 262
Helmut64 0:56dd5df33ab4 263 drawHorizontalLine(x0 - x, y0 - y, 2*x);
Helmut64 0:56dd5df33ab4 264 drawHorizontalLine(x0 - x, y0 + y, 2*x);
Helmut64 0:56dd5df33ab4 265 drawHorizontalLine(x0 - y, y0 - x, 2*y);
Helmut64 0:56dd5df33ab4 266 drawHorizontalLine(x0 - y, y0 + x, 2*y);
Helmut64 0:56dd5df33ab4 267
Helmut64 0:56dd5df33ab4 268
Helmut64 0:56dd5df33ab4 269 } while (x < y);
Helmut64 0:56dd5df33ab4 270 drawHorizontalLine(x0 - radius, y0, 2 * radius);
Helmut64 0:56dd5df33ab4 271
Helmut64 0:56dd5df33ab4 272 }
Helmut64 0:56dd5df33ab4 273
Helmut64 0:56dd5df33ab4 274 void OLEDDisplay::drawHorizontalLine(int16_t x, int16_t y, int16_t length) {
Helmut64 0:56dd5df33ab4 275 if (y < 0 || y >= this->height()) { return; }
Helmut64 0:56dd5df33ab4 276
Helmut64 0:56dd5df33ab4 277 if (x < 0) {
Helmut64 0:56dd5df33ab4 278 length += x;
Helmut64 0:56dd5df33ab4 279 x = 0;
Helmut64 0:56dd5df33ab4 280 }
Helmut64 0:56dd5df33ab4 281
Helmut64 0:56dd5df33ab4 282 if ( (x + length) > this->width()) {
Helmut64 0:56dd5df33ab4 283 length = (this->width() - x);
Helmut64 0:56dd5df33ab4 284 }
Helmut64 0:56dd5df33ab4 285
Helmut64 0:56dd5df33ab4 286 if (length <= 0) { return; }
Helmut64 0:56dd5df33ab4 287
Helmut64 0:56dd5df33ab4 288 uint8_t * bufferPtr = buffer;
Helmut64 0:56dd5df33ab4 289 bufferPtr += (y >> 3) * this->width();
Helmut64 0:56dd5df33ab4 290 bufferPtr += x;
Helmut64 0:56dd5df33ab4 291
Helmut64 0:56dd5df33ab4 292 uint8_t drawBit = 1 << (y & 7);
Helmut64 0:56dd5df33ab4 293
Helmut64 0:56dd5df33ab4 294 switch (color) {
Helmut64 0:56dd5df33ab4 295 case WHITE: while (length--) {
Helmut64 0:56dd5df33ab4 296 *bufferPtr++ |= drawBit;
Helmut64 0:56dd5df33ab4 297 }; break;
Helmut64 0:56dd5df33ab4 298 case BLACK: drawBit = ~drawBit; while (length--) {
Helmut64 0:56dd5df33ab4 299 *bufferPtr++ &= drawBit;
Helmut64 0:56dd5df33ab4 300 }; break;
Helmut64 0:56dd5df33ab4 301 case INVERSE: while (length--) {
Helmut64 0:56dd5df33ab4 302 *bufferPtr++ ^= drawBit;
Helmut64 0:56dd5df33ab4 303 }; break;
Helmut64 0:56dd5df33ab4 304 }
Helmut64 0:56dd5df33ab4 305 }
Helmut64 0:56dd5df33ab4 306
Helmut64 0:56dd5df33ab4 307 void OLEDDisplay::drawVerticalLine(int16_t x, int16_t y, int16_t length) {
Helmut64 0:56dd5df33ab4 308 if (x < 0 || x >= this->width()) return;
Helmut64 0:56dd5df33ab4 309
Helmut64 0:56dd5df33ab4 310 if (y < 0) {
Helmut64 0:56dd5df33ab4 311 length += y;
Helmut64 0:56dd5df33ab4 312 y = 0;
Helmut64 0:56dd5df33ab4 313 }
Helmut64 0:56dd5df33ab4 314
Helmut64 0:56dd5df33ab4 315 if ( (y + length) > this->height()) {
Helmut64 0:56dd5df33ab4 316 length = (this->height() - y);
Helmut64 0:56dd5df33ab4 317 }
Helmut64 0:56dd5df33ab4 318
Helmut64 0:56dd5df33ab4 319 if (length <= 0) return;
Helmut64 0:56dd5df33ab4 320
Helmut64 0:56dd5df33ab4 321
Helmut64 0:56dd5df33ab4 322 uint8_t yOffset = y & 7;
Helmut64 0:56dd5df33ab4 323 uint8_t drawBit;
Helmut64 0:56dd5df33ab4 324 uint8_t *bufferPtr = buffer;
Helmut64 0:56dd5df33ab4 325
Helmut64 0:56dd5df33ab4 326 bufferPtr += (y >> 3) * this->width();
Helmut64 0:56dd5df33ab4 327 bufferPtr += x;
Helmut64 0:56dd5df33ab4 328
Helmut64 0:56dd5df33ab4 329 if (yOffset) {
Helmut64 0:56dd5df33ab4 330 yOffset = 8 - yOffset;
Helmut64 0:56dd5df33ab4 331 drawBit = ~(0xFF >> (yOffset));
Helmut64 0:56dd5df33ab4 332
Helmut64 0:56dd5df33ab4 333 if (length < yOffset) {
Helmut64 0:56dd5df33ab4 334 drawBit &= (0xFF >> (yOffset - length));
Helmut64 0:56dd5df33ab4 335 }
Helmut64 0:56dd5df33ab4 336
Helmut64 0:56dd5df33ab4 337 switch (color) {
Helmut64 0:56dd5df33ab4 338 case WHITE: *bufferPtr |= drawBit; break;
Helmut64 0:56dd5df33ab4 339 case BLACK: *bufferPtr &= ~drawBit; break;
Helmut64 0:56dd5df33ab4 340 case INVERSE: *bufferPtr ^= drawBit; break;
Helmut64 0:56dd5df33ab4 341 }
Helmut64 0:56dd5df33ab4 342
Helmut64 0:56dd5df33ab4 343 if (length < yOffset) return;
Helmut64 0:56dd5df33ab4 344
Helmut64 0:56dd5df33ab4 345 length -= yOffset;
Helmut64 0:56dd5df33ab4 346 bufferPtr += this->width();
Helmut64 0:56dd5df33ab4 347 }
Helmut64 0:56dd5df33ab4 348
Helmut64 0:56dd5df33ab4 349 if (length >= 8) {
Helmut64 0:56dd5df33ab4 350 switch (color) {
Helmut64 0:56dd5df33ab4 351 case WHITE:
Helmut64 0:56dd5df33ab4 352 case BLACK:
Helmut64 0:56dd5df33ab4 353 drawBit = (color == WHITE) ? 0xFF : 0x00;
Helmut64 0:56dd5df33ab4 354 do {
Helmut64 0:56dd5df33ab4 355 *bufferPtr = drawBit;
Helmut64 0:56dd5df33ab4 356 bufferPtr += this->width();
Helmut64 0:56dd5df33ab4 357 length -= 8;
Helmut64 0:56dd5df33ab4 358 } while (length >= 8);
Helmut64 0:56dd5df33ab4 359 break;
Helmut64 0:56dd5df33ab4 360 case INVERSE:
Helmut64 0:56dd5df33ab4 361 do {
Helmut64 0:56dd5df33ab4 362 *bufferPtr = ~(*bufferPtr);
Helmut64 0:56dd5df33ab4 363 bufferPtr += this->width();
Helmut64 0:56dd5df33ab4 364 length -= 8;
Helmut64 0:56dd5df33ab4 365 } while (length >= 8);
Helmut64 0:56dd5df33ab4 366 break;
Helmut64 0:56dd5df33ab4 367 }
Helmut64 0:56dd5df33ab4 368 }
Helmut64 0:56dd5df33ab4 369
Helmut64 0:56dd5df33ab4 370 if (length > 0) {
Helmut64 0:56dd5df33ab4 371 drawBit = (1 << (length & 7)) - 1;
Helmut64 0:56dd5df33ab4 372 switch (color) {
Helmut64 0:56dd5df33ab4 373 case WHITE: *bufferPtr |= drawBit; break;
Helmut64 0:56dd5df33ab4 374 case BLACK: *bufferPtr &= ~drawBit; break;
Helmut64 0:56dd5df33ab4 375 case INVERSE: *bufferPtr ^= drawBit; break;
Helmut64 0:56dd5df33ab4 376 }
Helmut64 0:56dd5df33ab4 377 }
Helmut64 0:56dd5df33ab4 378 }
Helmut64 0:56dd5df33ab4 379
Helmut64 0:56dd5df33ab4 380 void OLEDDisplay::drawProgressBar(uint16_t x, uint16_t y, uint16_t width, uint16_t height, uint8_t progress) {
Helmut64 0:56dd5df33ab4 381 uint16_t radius = height / 2;
Helmut64 0:56dd5df33ab4 382 uint16_t xRadius = x + radius;
Helmut64 0:56dd5df33ab4 383 uint16_t yRadius = y + radius;
Helmut64 0:56dd5df33ab4 384 uint16_t doubleRadius = 2 * radius;
Helmut64 0:56dd5df33ab4 385 uint16_t innerRadius = radius - 2;
Helmut64 0:56dd5df33ab4 386
Helmut64 0:56dd5df33ab4 387 setColor(WHITE);
Helmut64 0:56dd5df33ab4 388 drawCircleQuads(xRadius, yRadius, radius, 0b00000110);
Helmut64 0:56dd5df33ab4 389 drawHorizontalLine(xRadius, y, width - doubleRadius + 1);
Helmut64 0:56dd5df33ab4 390 drawHorizontalLine(xRadius, y + height, width - doubleRadius + 1);
Helmut64 0:56dd5df33ab4 391 drawCircleQuads(x + width - radius, yRadius, radius, 0b00001001);
Helmut64 0:56dd5df33ab4 392
Helmut64 0:56dd5df33ab4 393 uint16_t maxProgressWidth = (width - doubleRadius + 1) * progress / 100;
Helmut64 0:56dd5df33ab4 394
Helmut64 0:56dd5df33ab4 395 fillCircle(xRadius, yRadius, innerRadius);
Helmut64 0:56dd5df33ab4 396 fillRect(xRadius + 1, y + 2, maxProgressWidth, height - 3);
Helmut64 0:56dd5df33ab4 397 fillCircle(xRadius + maxProgressWidth, yRadius, innerRadius);
Helmut64 0:56dd5df33ab4 398 }
Helmut64 0:56dd5df33ab4 399
Helmut64 0:56dd5df33ab4 400 void OLEDDisplay::drawFastImage(int16_t xMove, int16_t yMove, int16_t width, int16_t height, const uint8_t *image) {
Helmut64 0:56dd5df33ab4 401 drawInternal(xMove, yMove, width, height, image, 0, 0);
Helmut64 0:56dd5df33ab4 402 }
Helmut64 0:56dd5df33ab4 403
Helmut64 0:56dd5df33ab4 404 void OLEDDisplay::drawXbm(int16_t xMove, int16_t yMove, int16_t width, int16_t height, const uint8_t *xbm) {
Helmut64 0:56dd5df33ab4 405 int16_t widthInXbm = (width + 7) / 8;
Helmut64 0:56dd5df33ab4 406 uint8_t data = 0;
Helmut64 0:56dd5df33ab4 407
Helmut64 0:56dd5df33ab4 408 for(int16_t y = 0; y < height; y++) {
Helmut64 0:56dd5df33ab4 409 for(int16_t x = 0; x < width; x++ ) {
Helmut64 0:56dd5df33ab4 410 if (x & 7) {
Helmut64 0:56dd5df33ab4 411 data >>= 1; // Move a bit
Helmut64 0:56dd5df33ab4 412 } else { // Read new data every 8 bit
Helmut64 0:56dd5df33ab4 413 data = pgm_read_byte(xbm + (x / 8) + y * widthInXbm);
Helmut64 0:56dd5df33ab4 414 }
Helmut64 0:56dd5df33ab4 415 // if there is a bit draw it
Helmut64 0:56dd5df33ab4 416 if (data & 0x01) {
Helmut64 0:56dd5df33ab4 417 setPixel(xMove + x, yMove + y);
Helmut64 0:56dd5df33ab4 418 }
Helmut64 0:56dd5df33ab4 419 }
Helmut64 0:56dd5df33ab4 420 }
Helmut64 0:56dd5df33ab4 421 }
Helmut64 0:56dd5df33ab4 422
Helmut64 0:56dd5df33ab4 423 void OLEDDisplay::drawStringInternal(int16_t xMove, int16_t yMove, char* text, uint16_t textLength, uint16_t textWidth) {
Helmut64 0:56dd5df33ab4 424 uint8_t textHeight = pgm_read_byte(fontData + HEIGHT_POS);
Helmut64 0:56dd5df33ab4 425 uint8_t firstChar = pgm_read_byte(fontData + FIRST_CHAR_POS);
Helmut64 0:56dd5df33ab4 426 uint16_t sizeOfJumpTable = pgm_read_byte(fontData + CHAR_NUM_POS) * JUMPTABLE_BYTES;
Helmut64 0:56dd5df33ab4 427
Helmut64 0:56dd5df33ab4 428 uint8_t cursorX = 0;
Helmut64 0:56dd5df33ab4 429 uint8_t cursorY = 0;
Helmut64 0:56dd5df33ab4 430
Helmut64 0:56dd5df33ab4 431 switch (textAlignment) {
Helmut64 0:56dd5df33ab4 432 case TEXT_ALIGN_CENTER_BOTH:
Helmut64 0:56dd5df33ab4 433 yMove -= textHeight >> 1;
Helmut64 0:56dd5df33ab4 434 // Fallthrough
Helmut64 0:56dd5df33ab4 435 case TEXT_ALIGN_CENTER:
Helmut64 0:56dd5df33ab4 436 xMove -= textWidth >> 1; // divide by 2
Helmut64 0:56dd5df33ab4 437 break;
Helmut64 0:56dd5df33ab4 438 case TEXT_ALIGN_RIGHT:
Helmut64 0:56dd5df33ab4 439 xMove -= textWidth;
Helmut64 0:56dd5df33ab4 440 break;
Helmut64 0:56dd5df33ab4 441 case TEXT_ALIGN_LEFT:
Helmut64 0:56dd5df33ab4 442 break;
Helmut64 0:56dd5df33ab4 443 }
Helmut64 0:56dd5df33ab4 444
Helmut64 0:56dd5df33ab4 445 // Don't draw anything if it is not on the screen.
Helmut64 0:56dd5df33ab4 446 if (xMove + textWidth < 0 || xMove > this->width() ) {return;}
Helmut64 0:56dd5df33ab4 447 if (yMove + textHeight < 0 || yMove > this->width() ) {return;}
Helmut64 0:56dd5df33ab4 448
Helmut64 0:56dd5df33ab4 449 for (uint16_t j = 0; j < textLength; j++) {
Helmut64 0:56dd5df33ab4 450 int16_t xPos = xMove + cursorX;
Helmut64 0:56dd5df33ab4 451 int16_t yPos = yMove + cursorY;
Helmut64 0:56dd5df33ab4 452
Helmut64 0:56dd5df33ab4 453 uint8_t code = text[j];
Helmut64 0:56dd5df33ab4 454 if (code >= firstChar) {
Helmut64 0:56dd5df33ab4 455 uint8_t charCode = code - firstChar;
Helmut64 0:56dd5df33ab4 456
Helmut64 0:56dd5df33ab4 457 // 4 Bytes per char code
Helmut64 0:56dd5df33ab4 458 uint8_t msbJumpToChar = pgm_read_byte( fontData + JUMPTABLE_START + charCode * JUMPTABLE_BYTES ); // MSB \ JumpAddress
Helmut64 0:56dd5df33ab4 459 uint8_t lsbJumpToChar = pgm_read_byte( fontData + JUMPTABLE_START + charCode * JUMPTABLE_BYTES + JUMPTABLE_LSB); // LSB /
Helmut64 0:56dd5df33ab4 460 uint8_t charByteSize = pgm_read_byte( fontData + JUMPTABLE_START + charCode * JUMPTABLE_BYTES + JUMPTABLE_SIZE); // Size
Helmut64 0:56dd5df33ab4 461 uint8_t currentCharWidth = pgm_read_byte( fontData + JUMPTABLE_START + charCode * JUMPTABLE_BYTES + JUMPTABLE_WIDTH); // Width
Helmut64 0:56dd5df33ab4 462
Helmut64 0:56dd5df33ab4 463 // Test if the char is drawable
Helmut64 0:56dd5df33ab4 464 if (!(msbJumpToChar == 255 && lsbJumpToChar == 255)) {
Helmut64 0:56dd5df33ab4 465 // Get the position of the char data
Helmut64 0:56dd5df33ab4 466 uint16_t charDataPosition = JUMPTABLE_START + sizeOfJumpTable + ((msbJumpToChar << 8) + lsbJumpToChar);
Helmut64 0:56dd5df33ab4 467 drawInternal(xPos, yPos, currentCharWidth, textHeight, fontData, charDataPosition, charByteSize);
Helmut64 0:56dd5df33ab4 468 }
Helmut64 0:56dd5df33ab4 469
Helmut64 0:56dd5df33ab4 470 cursorX += currentCharWidth;
Helmut64 0:56dd5df33ab4 471 }
Helmut64 0:56dd5df33ab4 472 }
Helmut64 0:56dd5df33ab4 473 }
Helmut64 0:56dd5df33ab4 474
Helmut64 0:56dd5df33ab4 475
Helmut64 0:56dd5df33ab4 476 void OLEDDisplay::drawString(int16_t xMove, int16_t yMove, String strUser) {
Helmut64 0:56dd5df33ab4 477 uint16_t lineHeight = pgm_read_byte(fontData + HEIGHT_POS);
Helmut64 0:56dd5df33ab4 478
Helmut64 0:56dd5df33ab4 479 // char* text must be freed!
Helmut64 0:56dd5df33ab4 480 char* text = utf8ascii(strUser);
Helmut64 0:56dd5df33ab4 481
Helmut64 0:56dd5df33ab4 482 uint16_t yOffset = 0;
Helmut64 0:56dd5df33ab4 483 // If the string should be centered vertically too
Helmut64 0:56dd5df33ab4 484 // we need to now how heigh the string is.
Helmut64 0:56dd5df33ab4 485 if (textAlignment == TEXT_ALIGN_CENTER_BOTH) {
Helmut64 0:56dd5df33ab4 486 uint16_t lb = 0;
Helmut64 0:56dd5df33ab4 487 // Find number of linebreaks in text
Helmut64 0:56dd5df33ab4 488 for (uint16_t i=0;text[i] != 0; i++) {
Helmut64 0:56dd5df33ab4 489 lb += (text[i] == 10);
Helmut64 0:56dd5df33ab4 490 }
Helmut64 0:56dd5df33ab4 491 // Calculate center
Helmut64 0:56dd5df33ab4 492 yOffset = (lb * lineHeight) / 2;
Helmut64 0:56dd5df33ab4 493 }
Helmut64 0:56dd5df33ab4 494
Helmut64 0:56dd5df33ab4 495 uint16_t line = 0;
Helmut64 0:56dd5df33ab4 496 char* textPart = strtok(text,"\n");
Helmut64 0:56dd5df33ab4 497 while (textPart != NULL) {
Helmut64 0:56dd5df33ab4 498 uint16_t length = strlen(textPart);
Helmut64 0:56dd5df33ab4 499 drawStringInternal(xMove, yMove - yOffset + (line++) * lineHeight, textPart, length, getStringWidth(textPart, length));
Helmut64 0:56dd5df33ab4 500 textPart = strtok(NULL, "\n");
Helmut64 0:56dd5df33ab4 501 }
Helmut64 0:56dd5df33ab4 502 free(text);
Helmut64 0:56dd5df33ab4 503 }
Helmut64 0:56dd5df33ab4 504
Helmut64 0:56dd5df33ab4 505 void OLEDDisplay::drawStringMaxWidth(int16_t xMove, int16_t yMove, uint16_t maxLineWidth, String strUser) {
Helmut64 0:56dd5df33ab4 506 uint16_t firstChar = pgm_read_byte(fontData + FIRST_CHAR_POS);
Helmut64 0:56dd5df33ab4 507 uint16_t lineHeight = pgm_read_byte(fontData + HEIGHT_POS);
Helmut64 0:56dd5df33ab4 508
Helmut64 0:56dd5df33ab4 509 char* text = utf8ascii(strUser);
Helmut64 0:56dd5df33ab4 510
Helmut64 0:56dd5df33ab4 511 uint16_t length = strlen(text);
Helmut64 0:56dd5df33ab4 512 uint16_t lastDrawnPos = 0;
Helmut64 0:56dd5df33ab4 513 uint16_t lineNumber = 0;
Helmut64 0:56dd5df33ab4 514 uint16_t strWidth = 0;
Helmut64 0:56dd5df33ab4 515
Helmut64 0:56dd5df33ab4 516 uint16_t preferredBreakpoint = 0;
Helmut64 0:56dd5df33ab4 517 uint16_t widthAtBreakpoint = 0;
Helmut64 0:56dd5df33ab4 518
Helmut64 0:56dd5df33ab4 519 for (uint16_t i = 0; i < length; i++) {
Helmut64 0:56dd5df33ab4 520 strWidth += pgm_read_byte(fontData + JUMPTABLE_START + (text[i] - firstChar) * JUMPTABLE_BYTES + JUMPTABLE_WIDTH);
Helmut64 0:56dd5df33ab4 521
Helmut64 0:56dd5df33ab4 522 // Always try to break on a space or dash
Helmut64 0:56dd5df33ab4 523 if (text[i] == ' ' || text[i]== '-') {
Helmut64 0:56dd5df33ab4 524 preferredBreakpoint = i;
Helmut64 0:56dd5df33ab4 525 widthAtBreakpoint = strWidth;
Helmut64 0:56dd5df33ab4 526 }
Helmut64 0:56dd5df33ab4 527
Helmut64 0:56dd5df33ab4 528 if (strWidth >= maxLineWidth) {
Helmut64 0:56dd5df33ab4 529 if (preferredBreakpoint == 0) {
Helmut64 0:56dd5df33ab4 530 preferredBreakpoint = i;
Helmut64 0:56dd5df33ab4 531 widthAtBreakpoint = strWidth;
Helmut64 0:56dd5df33ab4 532 }
Helmut64 0:56dd5df33ab4 533 drawStringInternal(xMove, yMove + (lineNumber++) * lineHeight , &text[lastDrawnPos], preferredBreakpoint - lastDrawnPos, widthAtBreakpoint);
Helmut64 0:56dd5df33ab4 534 lastDrawnPos = preferredBreakpoint + 1;
Helmut64 0:56dd5df33ab4 535 // It is possible that we did not draw all letters to i so we need
Helmut64 0:56dd5df33ab4 536 // to account for the width of the chars from `i - preferredBreakpoint`
Helmut64 0:56dd5df33ab4 537 // by calculating the width we did not draw yet.
Helmut64 0:56dd5df33ab4 538 strWidth = strWidth - widthAtBreakpoint;
Helmut64 0:56dd5df33ab4 539 preferredBreakpoint = 0;
Helmut64 0:56dd5df33ab4 540 }
Helmut64 0:56dd5df33ab4 541 }
Helmut64 0:56dd5df33ab4 542
Helmut64 0:56dd5df33ab4 543 // Draw last part if needed
Helmut64 0:56dd5df33ab4 544 if (lastDrawnPos < length) {
Helmut64 0:56dd5df33ab4 545 drawStringInternal(xMove, yMove + lineNumber * lineHeight , &text[lastDrawnPos], length - lastDrawnPos, getStringWidth(&text[lastDrawnPos], length - lastDrawnPos));
Helmut64 0:56dd5df33ab4 546 }
Helmut64 0:56dd5df33ab4 547
Helmut64 0:56dd5df33ab4 548 free(text);
Helmut64 0:56dd5df33ab4 549 }
Helmut64 0:56dd5df33ab4 550
Helmut64 0:56dd5df33ab4 551 uint16_t OLEDDisplay::getStringWidth(const char* text, uint16_t length) {
Helmut64 0:56dd5df33ab4 552 uint16_t firstChar = pgm_read_byte(fontData + FIRST_CHAR_POS);
Helmut64 0:56dd5df33ab4 553
Helmut64 0:56dd5df33ab4 554 uint16_t stringWidth = 0;
Helmut64 0:56dd5df33ab4 555 uint16_t maxWidth = 0;
Helmut64 0:56dd5df33ab4 556
Helmut64 0:56dd5df33ab4 557 while (length--) {
Helmut64 0:56dd5df33ab4 558 stringWidth += pgm_read_byte(fontData + JUMPTABLE_START + (text[length] - firstChar) * JUMPTABLE_BYTES + JUMPTABLE_WIDTH);
Helmut64 0:56dd5df33ab4 559 if (text[length] == 10) {
Helmut64 0:56dd5df33ab4 560 maxWidth = max(maxWidth, stringWidth);
Helmut64 0:56dd5df33ab4 561 stringWidth = 0;
Helmut64 0:56dd5df33ab4 562 }
Helmut64 0:56dd5df33ab4 563 }
Helmut64 0:56dd5df33ab4 564
Helmut64 0:56dd5df33ab4 565 return max(maxWidth, stringWidth);
Helmut64 0:56dd5df33ab4 566 }
Helmut64 0:56dd5df33ab4 567
Helmut64 0:56dd5df33ab4 568 uint16_t OLEDDisplay::getStringWidth(String strUser) {
Helmut64 0:56dd5df33ab4 569 char* text = utf8ascii(strUser);
Helmut64 0:56dd5df33ab4 570 uint16_t length = strlen(text);
Helmut64 0:56dd5df33ab4 571 uint16_t width = getStringWidth(text, length);
Helmut64 0:56dd5df33ab4 572 free(text);
Helmut64 0:56dd5df33ab4 573 return width;
Helmut64 0:56dd5df33ab4 574 }
Helmut64 0:56dd5df33ab4 575
Helmut64 0:56dd5df33ab4 576 void OLEDDisplay::setTextAlignment(OLEDDISPLAY_TEXT_ALIGNMENT textAlignment) {
Helmut64 0:56dd5df33ab4 577 this->textAlignment = textAlignment;
Helmut64 0:56dd5df33ab4 578 }
Helmut64 0:56dd5df33ab4 579
Helmut64 0:56dd5df33ab4 580 void OLEDDisplay::setFont(const uint8_t *fontData) {
Helmut64 0:56dd5df33ab4 581 this->fontData = fontData;
Helmut64 0:56dd5df33ab4 582 }
Helmut64 0:56dd5df33ab4 583
Helmut64 0:56dd5df33ab4 584 void OLEDDisplay::displayOn(void) {
Helmut64 0:56dd5df33ab4 585 sendCommand(DISPLAYON);
Helmut64 0:56dd5df33ab4 586 }
Helmut64 0:56dd5df33ab4 587
Helmut64 0:56dd5df33ab4 588 void OLEDDisplay::displayOff(void) {
Helmut64 0:56dd5df33ab4 589 sendCommand(DISPLAYOFF);
Helmut64 0:56dd5df33ab4 590 }
Helmut64 0:56dd5df33ab4 591
Helmut64 0:56dd5df33ab4 592 void OLEDDisplay::invertDisplay(void) {
Helmut64 0:56dd5df33ab4 593 sendCommand(INVERTDISPLAY);
Helmut64 0:56dd5df33ab4 594 }
Helmut64 0:56dd5df33ab4 595
Helmut64 0:56dd5df33ab4 596 void OLEDDisplay::normalDisplay(void) {
Helmut64 0:56dd5df33ab4 597 sendCommand(NORMALDISPLAY);
Helmut64 0:56dd5df33ab4 598 }
Helmut64 0:56dd5df33ab4 599
Helmut64 0:56dd5df33ab4 600 void OLEDDisplay::setContrast(uint8_t contrast, uint8_t precharge, uint8_t comdetect) {
Helmut64 0:56dd5df33ab4 601 sendCommand(SETPRECHARGE); //0xD9
Helmut64 0:56dd5df33ab4 602 sendCommand(precharge); //0xF1 default, to lower the contrast, put 1-1F
Helmut64 0:56dd5df33ab4 603 sendCommand(SETCONTRAST);
Helmut64 0:56dd5df33ab4 604 sendCommand(contrast); // 0-255
Helmut64 0:56dd5df33ab4 605 sendCommand(SETVCOMDETECT); //0xDB, (additionally needed to lower the contrast)
Helmut64 0:56dd5df33ab4 606 sendCommand(comdetect); //0x40 default, to lower the contrast, put 0
Helmut64 0:56dd5df33ab4 607 sendCommand(DISPLAYALLON_RESUME);
Helmut64 0:56dd5df33ab4 608 sendCommand(NORMALDISPLAY);
Helmut64 0:56dd5df33ab4 609 sendCommand(DISPLAYON);
Helmut64 0:56dd5df33ab4 610 }
Helmut64 0:56dd5df33ab4 611
Helmut64 0:56dd5df33ab4 612 void OLEDDisplay::setBrightness(uint8_t brightness) {
Helmut64 0:56dd5df33ab4 613 uint8_t contrast = brightness;
Helmut64 0:56dd5df33ab4 614 if (brightness < 128) {
Helmut64 0:56dd5df33ab4 615 // Magic values to get a smooth/ step-free transition
Helmut64 0:56dd5df33ab4 616 contrast = brightness * 1.171;
Helmut64 0:56dd5df33ab4 617 } else {
Helmut64 0:56dd5df33ab4 618 contrast = brightness * 1.171 - 43;
Helmut64 0:56dd5df33ab4 619 }
Helmut64 0:56dd5df33ab4 620
Helmut64 0:56dd5df33ab4 621 uint8_t precharge = 241;
Helmut64 0:56dd5df33ab4 622 if (brightness == 0) {
Helmut64 0:56dd5df33ab4 623 precharge = 0;
Helmut64 0:56dd5df33ab4 624 }
Helmut64 0:56dd5df33ab4 625 uint8_t comdetect = brightness / 8;
Helmut64 0:56dd5df33ab4 626
Helmut64 0:56dd5df33ab4 627 setContrast(contrast, precharge, comdetect);
Helmut64 0:56dd5df33ab4 628 }
Helmut64 0:56dd5df33ab4 629
Helmut64 0:56dd5df33ab4 630 void OLEDDisplay::resetOrientation() {
Helmut64 0:56dd5df33ab4 631 sendCommand(SEGREMAP);
Helmut64 0:56dd5df33ab4 632 sendCommand(COMSCANINC); //Reset screen rotation or mirroring
Helmut64 0:56dd5df33ab4 633 }
Helmut64 0:56dd5df33ab4 634
Helmut64 0:56dd5df33ab4 635 void OLEDDisplay::flipScreenVertically() {
Helmut64 0:56dd5df33ab4 636 sendCommand(SEGREMAP | 0x01);
Helmut64 0:56dd5df33ab4 637 sendCommand(COMSCANDEC); //Rotate screen 180 Deg
Helmut64 0:56dd5df33ab4 638 }
Helmut64 0:56dd5df33ab4 639
Helmut64 0:56dd5df33ab4 640 void OLEDDisplay::mirrorScreen() {
Helmut64 0:56dd5df33ab4 641 sendCommand(SEGREMAP);
Helmut64 0:56dd5df33ab4 642 sendCommand(COMSCANDEC); //Mirror screen
Helmut64 0:56dd5df33ab4 643 }
Helmut64 0:56dd5df33ab4 644
Helmut64 0:56dd5df33ab4 645 void OLEDDisplay::clear(void) {
Helmut64 0:56dd5df33ab4 646 memset(buffer, 0, displayBufferSize);
Helmut64 0:56dd5df33ab4 647 }
Helmut64 0:56dd5df33ab4 648
Helmut64 0:56dd5df33ab4 649 void OLEDDisplay::drawLogBuffer(uint16_t xMove, uint16_t yMove) {
Helmut64 0:56dd5df33ab4 650 uint16_t lineHeight = pgm_read_byte(fontData + HEIGHT_POS);
Helmut64 0:56dd5df33ab4 651 // Always align left
Helmut64 0:56dd5df33ab4 652 setTextAlignment(TEXT_ALIGN_LEFT);
Helmut64 0:56dd5df33ab4 653
Helmut64 0:56dd5df33ab4 654 // State values
Helmut64 0:56dd5df33ab4 655 uint16_t length = 0;
Helmut64 0:56dd5df33ab4 656 uint16_t line = 0;
Helmut64 0:56dd5df33ab4 657 uint16_t lastPos = 0;
Helmut64 0:56dd5df33ab4 658
Helmut64 0:56dd5df33ab4 659 for (uint16_t i=0;i<this->logBufferFilled;i++){
Helmut64 0:56dd5df33ab4 660 // Everytime we have a \n print
Helmut64 0:56dd5df33ab4 661 if (this->logBuffer[i] == 10) {
Helmut64 0:56dd5df33ab4 662 length++;
Helmut64 0:56dd5df33ab4 663 // Draw string on line `line` from lastPos to length
Helmut64 0:56dd5df33ab4 664 // Passing 0 as the lenght because we are in TEXT_ALIGN_LEFT
Helmut64 0:56dd5df33ab4 665 drawStringInternal(xMove, yMove + (line++) * lineHeight, &this->logBuffer[lastPos], length, 0);
Helmut64 0:56dd5df33ab4 666 // Remember last pos
Helmut64 0:56dd5df33ab4 667 lastPos = i;
Helmut64 0:56dd5df33ab4 668 // Reset length
Helmut64 0:56dd5df33ab4 669 length = 0;
Helmut64 0:56dd5df33ab4 670 } else {
Helmut64 0:56dd5df33ab4 671 // Count chars until next linebreak
Helmut64 0:56dd5df33ab4 672 length++;
Helmut64 0:56dd5df33ab4 673 }
Helmut64 0:56dd5df33ab4 674 }
Helmut64 0:56dd5df33ab4 675 // Draw the remaining string
Helmut64 0:56dd5df33ab4 676 if (length > 0) {
Helmut64 0:56dd5df33ab4 677 drawStringInternal(xMove, yMove + line * lineHeight, &this->logBuffer[lastPos], length, 0);
Helmut64 0:56dd5df33ab4 678 }
Helmut64 0:56dd5df33ab4 679 }
Helmut64 0:56dd5df33ab4 680
Helmut64 0:56dd5df33ab4 681 uint16_t OLEDDisplay::getWidth(void) {
Helmut64 0:56dd5df33ab4 682 return displayWidth;
Helmut64 0:56dd5df33ab4 683 }
Helmut64 0:56dd5df33ab4 684
Helmut64 0:56dd5df33ab4 685 uint16_t OLEDDisplay::getHeight(void) {
Helmut64 0:56dd5df33ab4 686 return displayHeight;
Helmut64 0:56dd5df33ab4 687 }
Helmut64 0:56dd5df33ab4 688
Helmut64 0:56dd5df33ab4 689 bool OLEDDisplay::setLogBuffer(uint16_t lines, uint16_t chars){
Helmut64 0:56dd5df33ab4 690 if (logBuffer != NULL) free(logBuffer);
Helmut64 0:56dd5df33ab4 691 uint16_t size = lines * chars;
Helmut64 0:56dd5df33ab4 692 if (size > 0) {
Helmut64 0:56dd5df33ab4 693 this->logBufferLine = 0; // Lines printed
Helmut64 0:56dd5df33ab4 694 this->logBufferFilled = 0; // Nothing stored yet
Helmut64 0:56dd5df33ab4 695 this->logBufferMaxLines = lines; // Lines max printable
Helmut64 0:56dd5df33ab4 696 this->logBufferSize = size; // Total number of characters the buffer can hold
Helmut64 0:56dd5df33ab4 697 this->logBuffer = (char *) malloc(size * sizeof(uint8_t));
Helmut64 0:56dd5df33ab4 698 if(!this->logBuffer) {
Helmut64 0:56dd5df33ab4 699 DEBUG_OLEDDISPLAY("[OLEDDISPLAY][setLogBuffer] Not enough memory to create log buffer\n");
Helmut64 0:56dd5df33ab4 700 return false;
Helmut64 0:56dd5df33ab4 701 }
Helmut64 0:56dd5df33ab4 702 }
Helmut64 0:56dd5df33ab4 703 return true;
Helmut64 0:56dd5df33ab4 704 }
Helmut64 0:56dd5df33ab4 705
Helmut64 0:56dd5df33ab4 706 size_t OLEDDisplay::write(uint8_t c) {
Helmut64 0:56dd5df33ab4 707 if (this->logBufferSize > 0) {
Helmut64 0:56dd5df33ab4 708 // Don't waste space on \r\n line endings, dropping \r
Helmut64 0:56dd5df33ab4 709 if (c == 13) return 1;
Helmut64 0:56dd5df33ab4 710
Helmut64 0:56dd5df33ab4 711 // convert UTF-8 character to font table index
Helmut64 0:56dd5df33ab4 712 c = (this->fontTableLookupFunction)(c);
Helmut64 0:56dd5df33ab4 713 // drop unknown character
Helmut64 0:56dd5df33ab4 714 if (c == 0) return 1;
Helmut64 0:56dd5df33ab4 715
Helmut64 0:56dd5df33ab4 716 bool maxLineNotReached = this->logBufferLine < this->logBufferMaxLines;
Helmut64 0:56dd5df33ab4 717 bool bufferNotFull = this->logBufferFilled < this->logBufferSize;
Helmut64 0:56dd5df33ab4 718
Helmut64 0:56dd5df33ab4 719 // Can we write to the buffer?
Helmut64 0:56dd5df33ab4 720 if (bufferNotFull && maxLineNotReached) {
Helmut64 0:56dd5df33ab4 721 this->logBuffer[logBufferFilled] = c;
Helmut64 0:56dd5df33ab4 722 this->logBufferFilled++;
Helmut64 0:56dd5df33ab4 723 // Keep track of lines written
Helmut64 0:56dd5df33ab4 724 if (c == 10) this->logBufferLine++;
Helmut64 0:56dd5df33ab4 725 } else {
Helmut64 0:56dd5df33ab4 726 // Max line number is reached
Helmut64 0:56dd5df33ab4 727 if (!maxLineNotReached) this->logBufferLine--;
Helmut64 0:56dd5df33ab4 728
Helmut64 0:56dd5df33ab4 729 // Find the end of the first line
Helmut64 0:56dd5df33ab4 730 uint16_t firstLineEnd = 0;
Helmut64 0:56dd5df33ab4 731 for (uint16_t i=0;i<this->logBufferFilled;i++) {
Helmut64 0:56dd5df33ab4 732 if (this->logBuffer[i] == 10){
Helmut64 0:56dd5df33ab4 733 // Include last char too
Helmut64 0:56dd5df33ab4 734 firstLineEnd = i + 1;
Helmut64 0:56dd5df33ab4 735 break;
Helmut64 0:56dd5df33ab4 736 }
Helmut64 0:56dd5df33ab4 737 }
Helmut64 0:56dd5df33ab4 738 // If there was a line ending
Helmut64 0:56dd5df33ab4 739 if (firstLineEnd > 0) {
Helmut64 0:56dd5df33ab4 740 // Calculate the new logBufferFilled value
Helmut64 0:56dd5df33ab4 741 this->logBufferFilled = logBufferFilled - firstLineEnd;
Helmut64 0:56dd5df33ab4 742 // Now we move the lines infront of the buffer
Helmut64 0:56dd5df33ab4 743 memcpy(this->logBuffer, &this->logBuffer[firstLineEnd], logBufferFilled);
Helmut64 0:56dd5df33ab4 744 } else {
Helmut64 0:56dd5df33ab4 745 // Let's reuse the buffer if it was full
Helmut64 0:56dd5df33ab4 746 if (!bufferNotFull) {
Helmut64 0:56dd5df33ab4 747 this->logBufferFilled = 0;
Helmut64 0:56dd5df33ab4 748 }// else {
Helmut64 0:56dd5df33ab4 749 // Nothing to do here
Helmut64 0:56dd5df33ab4 750 //}
Helmut64 0:56dd5df33ab4 751 }
Helmut64 0:56dd5df33ab4 752 write(c);
Helmut64 0:56dd5df33ab4 753 }
Helmut64 0:56dd5df33ab4 754 }
Helmut64 0:56dd5df33ab4 755 // We are always writing all uint8_t to the buffer
Helmut64 0:56dd5df33ab4 756 return 1;
Helmut64 0:56dd5df33ab4 757 }
Helmut64 0:56dd5df33ab4 758
Helmut64 0:56dd5df33ab4 759 size_t OLEDDisplay::write(const char* str) {
Helmut64 0:56dd5df33ab4 760 if (str == NULL) return 0;
Helmut64 0:56dd5df33ab4 761 size_t length = strlen(str);
Helmut64 0:56dd5df33ab4 762 for (size_t i = 0; i < length; i++) {
Helmut64 0:56dd5df33ab4 763 write(str[i]);
Helmut64 0:56dd5df33ab4 764 }
Helmut64 0:56dd5df33ab4 765 return length;
Helmut64 0:56dd5df33ab4 766 }
Helmut64 0:56dd5df33ab4 767
Helmut64 0:56dd5df33ab4 768 #ifdef __MBED__
Helmut64 0:56dd5df33ab4 769 int OLEDDisplay::_putc(int c) {
Helmut64 0:56dd5df33ab4 770
Helmut64 0:56dd5df33ab4 771 if (!fontData)
Helmut64 0:56dd5df33ab4 772 return 1;
Helmut64 0:56dd5df33ab4 773 if (!logBufferSize) {
Helmut64 0:56dd5df33ab4 774 uint8_t textHeight = pgm_read_byte(fontData + HEIGHT_POS);
Helmut64 0:56dd5df33ab4 775 uint16_t lines = this->displayHeight / textHeight;
Helmut64 0:56dd5df33ab4 776 uint16_t chars = 2 * (this->displayWidth / textHeight);
Helmut64 0:56dd5df33ab4 777
Helmut64 0:56dd5df33ab4 778 if (this->displayHeight % textHeight)
Helmut64 0:56dd5df33ab4 779 lines++;
Helmut64 0:56dd5df33ab4 780 if (this->displayWidth % textHeight)
Helmut64 0:56dd5df33ab4 781 chars++;
Helmut64 0:56dd5df33ab4 782 setLogBuffer(lines, chars);
Helmut64 0:56dd5df33ab4 783 }
Helmut64 0:56dd5df33ab4 784
Helmut64 0:56dd5df33ab4 785 return this->write((uint8_t)c);
Helmut64 0:56dd5df33ab4 786 }
Helmut64 0:56dd5df33ab4 787 #endif
Helmut64 0:56dd5df33ab4 788
Helmut64 0:56dd5df33ab4 789 // Private functions
Helmut64 0:56dd5df33ab4 790 void OLEDDisplay::setGeometry(OLEDDISPLAY_GEOMETRY g) {
Helmut64 0:56dd5df33ab4 791 this->geometry = g;
Helmut64 0:56dd5df33ab4 792 if (g == GEOMETRY_128_64) {
Helmut64 0:56dd5df33ab4 793 this->displayWidth = 128;
Helmut64 0:56dd5df33ab4 794 this->displayHeight = 64;
Helmut64 0:56dd5df33ab4 795 } else if (g == GEOMETRY_128_32) {
Helmut64 0:56dd5df33ab4 796 this->displayWidth = 128;
Helmut64 0:56dd5df33ab4 797 this->displayHeight = 32;
Helmut64 0:56dd5df33ab4 798 }
Helmut64 0:56dd5df33ab4 799 this->displayBufferSize = displayWidth*displayHeight/8;
Helmut64 0:56dd5df33ab4 800 }
Helmut64 0:56dd5df33ab4 801
Helmut64 0:56dd5df33ab4 802 void OLEDDisplay::sendInitCommands(void) {
Helmut64 0:56dd5df33ab4 803 sendCommand(DISPLAYOFF);
Helmut64 0:56dd5df33ab4 804 sendCommand(SETDISPLAYCLOCKDIV);
Helmut64 0:56dd5df33ab4 805 sendCommand(0xF0); // Increase speed of the display max ~96Hz
Helmut64 0:56dd5df33ab4 806 sendCommand(SETMULTIPLEX);
Helmut64 0:56dd5df33ab4 807 sendCommand(this->height() - 1);
Helmut64 0:56dd5df33ab4 808 sendCommand(SETDISPLAYOFFSET);
Helmut64 0:56dd5df33ab4 809 sendCommand(0x00);
Helmut64 0:56dd5df33ab4 810 sendCommand(SETSTARTLINE);
Helmut64 0:56dd5df33ab4 811 sendCommand(CHARGEPUMP);
Helmut64 0:56dd5df33ab4 812 sendCommand(0x14);
Helmut64 0:56dd5df33ab4 813 sendCommand(MEMORYMODE);
Helmut64 0:56dd5df33ab4 814 sendCommand(0x00);
Helmut64 0:56dd5df33ab4 815 sendCommand(SEGREMAP);
Helmut64 0:56dd5df33ab4 816 sendCommand(COMSCANINC);
Helmut64 0:56dd5df33ab4 817 sendCommand(SETCOMPINS);
Helmut64 0:56dd5df33ab4 818
Helmut64 0:56dd5df33ab4 819 if (geometry == GEOMETRY_128_64) {
Helmut64 0:56dd5df33ab4 820 sendCommand(0x12);
Helmut64 0:56dd5df33ab4 821 } else if (geometry == GEOMETRY_128_32) {
Helmut64 0:56dd5df33ab4 822 sendCommand(0x02);
Helmut64 0:56dd5df33ab4 823 }
Helmut64 0:56dd5df33ab4 824
Helmut64 0:56dd5df33ab4 825 sendCommand(SETCONTRAST);
Helmut64 0:56dd5df33ab4 826
Helmut64 0:56dd5df33ab4 827 if (geometry == GEOMETRY_128_64) {
Helmut64 0:56dd5df33ab4 828 sendCommand(0xCF);
Helmut64 0:56dd5df33ab4 829 } else if (geometry == GEOMETRY_128_32) {
Helmut64 0:56dd5df33ab4 830 sendCommand(0x8F);
Helmut64 0:56dd5df33ab4 831 }
Helmut64 0:56dd5df33ab4 832
Helmut64 0:56dd5df33ab4 833 sendCommand(SETPRECHARGE);
Helmut64 0:56dd5df33ab4 834 sendCommand(0xF1);
Helmut64 0:56dd5df33ab4 835 sendCommand(SETVCOMDETECT); //0xDB, (additionally needed to lower the contrast)
Helmut64 0:56dd5df33ab4 836 sendCommand(0x40); //0x40 default, to lower the contrast, put 0
Helmut64 0:56dd5df33ab4 837 sendCommand(DISPLAYALLON_RESUME);
Helmut64 0:56dd5df33ab4 838 sendCommand(NORMALDISPLAY);
Helmut64 0:56dd5df33ab4 839 sendCommand(0x2e); // stop scroll
Helmut64 0:56dd5df33ab4 840 sendCommand(DISPLAYON);
Helmut64 0:56dd5df33ab4 841 }
Helmut64 0:56dd5df33ab4 842
Helmut64 0:56dd5df33ab4 843 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) {
Helmut64 0:56dd5df33ab4 844 if (width < 0 || height < 0) return;
Helmut64 0:56dd5df33ab4 845 if (yMove + height < 0 || yMove > this->height()) return;
Helmut64 0:56dd5df33ab4 846 if (xMove + width < 0 || xMove > this->width()) return;
Helmut64 0:56dd5df33ab4 847
Helmut64 0:56dd5df33ab4 848 uint8_t rasterHeight = 1 + ((height - 1) >> 3); // fast ceil(height / 8.0)
Helmut64 0:56dd5df33ab4 849 int8_t yOffset = yMove & 7;
Helmut64 0:56dd5df33ab4 850
Helmut64 0:56dd5df33ab4 851 bytesInData = bytesInData == 0 ? width * rasterHeight : bytesInData;
Helmut64 0:56dd5df33ab4 852
Helmut64 0:56dd5df33ab4 853 int16_t initYMove = yMove;
Helmut64 0:56dd5df33ab4 854 int8_t initYOffset = yOffset;
Helmut64 0:56dd5df33ab4 855
Helmut64 0:56dd5df33ab4 856
Helmut64 0:56dd5df33ab4 857 for (uint16_t i = 0; i < bytesInData; i++) {
Helmut64 0:56dd5df33ab4 858
Helmut64 0:56dd5df33ab4 859 // Reset if next horizontal drawing phase is started.
Helmut64 0:56dd5df33ab4 860 if ( i % rasterHeight == 0) {
Helmut64 0:56dd5df33ab4 861 yMove = initYMove;
Helmut64 0:56dd5df33ab4 862 yOffset = initYOffset;
Helmut64 0:56dd5df33ab4 863 }
Helmut64 0:56dd5df33ab4 864
Helmut64 0:56dd5df33ab4 865 uint8_t currentByte = pgm_read_byte(data + offset + i);
Helmut64 0:56dd5df33ab4 866
Helmut64 0:56dd5df33ab4 867 int16_t xPos = xMove + (i / rasterHeight);
Helmut64 0:56dd5df33ab4 868 int16_t yPos = ((yMove >> 3) + (i % rasterHeight)) * this->width();
Helmut64 0:56dd5df33ab4 869
Helmut64 0:56dd5df33ab4 870 // int16_t yScreenPos = yMove + yOffset;
Helmut64 0:56dd5df33ab4 871 int16_t dataPos = xPos + yPos;
Helmut64 0:56dd5df33ab4 872
Helmut64 0:56dd5df33ab4 873 if (dataPos >= 0 && dataPos < displayBufferSize &&
Helmut64 0:56dd5df33ab4 874 xPos >= 0 && xPos < this->width() ) {
Helmut64 0:56dd5df33ab4 875
Helmut64 0:56dd5df33ab4 876 if (yOffset >= 0) {
Helmut64 0:56dd5df33ab4 877 switch (this->color) {
Helmut64 0:56dd5df33ab4 878 case WHITE: buffer[dataPos] |= currentByte << yOffset; break;
Helmut64 0:56dd5df33ab4 879 case BLACK: buffer[dataPos] &= ~(currentByte << yOffset); break;
Helmut64 0:56dd5df33ab4 880 case INVERSE: buffer[dataPos] ^= currentByte << yOffset; break;
Helmut64 0:56dd5df33ab4 881 }
Helmut64 0:56dd5df33ab4 882
Helmut64 0:56dd5df33ab4 883 if (dataPos < (displayBufferSize - this->width())) {
Helmut64 0:56dd5df33ab4 884 switch (this->color) {
Helmut64 0:56dd5df33ab4 885 case WHITE: buffer[dataPos + this->width()] |= currentByte >> (8 - yOffset); break;
Helmut64 0:56dd5df33ab4 886 case BLACK: buffer[dataPos + this->width()] &= ~(currentByte >> (8 - yOffset)); break;
Helmut64 0:56dd5df33ab4 887 case INVERSE: buffer[dataPos + this->width()] ^= currentByte >> (8 - yOffset); break;
Helmut64 0:56dd5df33ab4 888 }
Helmut64 0:56dd5df33ab4 889 }
Helmut64 0:56dd5df33ab4 890 } else {
Helmut64 0:56dd5df33ab4 891 // Make new offset position
Helmut64 0:56dd5df33ab4 892 yOffset = -yOffset;
Helmut64 0:56dd5df33ab4 893
Helmut64 0:56dd5df33ab4 894 switch (this->color) {
Helmut64 0:56dd5df33ab4 895 case WHITE: buffer[dataPos] |= currentByte >> yOffset; break;
Helmut64 0:56dd5df33ab4 896 case BLACK: buffer[dataPos] &= ~(currentByte >> yOffset); break;
Helmut64 0:56dd5df33ab4 897 case INVERSE: buffer[dataPos] ^= currentByte >> yOffset; break;
Helmut64 0:56dd5df33ab4 898 }
Helmut64 0:56dd5df33ab4 899
Helmut64 0:56dd5df33ab4 900 // Prepare for next iteration by moving one block up
Helmut64 0:56dd5df33ab4 901 yMove -= 8;
Helmut64 0:56dd5df33ab4 902
Helmut64 0:56dd5df33ab4 903 // and setting the new yOffset
Helmut64 0:56dd5df33ab4 904 yOffset = 8 - yOffset;
Helmut64 0:56dd5df33ab4 905 }
Helmut64 0:56dd5df33ab4 906 #ifndef __MBED__
Helmut64 0:56dd5df33ab4 907 yield();
Helmut64 0:56dd5df33ab4 908 #endif
Helmut64 0:56dd5df33ab4 909 }
Helmut64 0:56dd5df33ab4 910 }
Helmut64 0:56dd5df33ab4 911 }
Helmut64 0:56dd5df33ab4 912
Helmut64 0:56dd5df33ab4 913 // You need to free the char!
Helmut64 0:56dd5df33ab4 914 char* OLEDDisplay::utf8ascii(String str) {
Helmut64 0:56dd5df33ab4 915 uint16_t k = 0;
Helmut64 0:56dd5df33ab4 916 uint16_t length = str.length() + 1;
Helmut64 0:56dd5df33ab4 917
Helmut64 0:56dd5df33ab4 918 // Copy the string into a char array
Helmut64 0:56dd5df33ab4 919 char* s = (char*) malloc(length * sizeof(char));
Helmut64 0:56dd5df33ab4 920 if(!s) {
Helmut64 0:56dd5df33ab4 921 DEBUG_OLEDDISPLAY("[OLEDDISPLAY][utf8ascii] Can't allocate another char array. Drop support for UTF-8.\n");
Helmut64 0:56dd5df33ab4 922 return (char*) str.c_str();
Helmut64 0:56dd5df33ab4 923 }
Helmut64 0:56dd5df33ab4 924 str.toCharArray(s, length);
Helmut64 0:56dd5df33ab4 925
Helmut64 0:56dd5df33ab4 926 length--;
Helmut64 0:56dd5df33ab4 927
Helmut64 0:56dd5df33ab4 928 for (uint16_t i=0; i < length; i++) {
Helmut64 0:56dd5df33ab4 929 char c = (this->fontTableLookupFunction)(s[i]);
Helmut64 0:56dd5df33ab4 930 if (c!=0) {
Helmut64 0:56dd5df33ab4 931 s[k++]=c;
Helmut64 0:56dd5df33ab4 932 }
Helmut64 0:56dd5df33ab4 933 }
Helmut64 0:56dd5df33ab4 934
Helmut64 0:56dd5df33ab4 935 s[k]=0;
Helmut64 0:56dd5df33ab4 936
Helmut64 0:56dd5df33ab4 937 // This will leak 's' be sure to free it in the calling function.
Helmut64 0:56dd5df33ab4 938 return s;
Helmut64 0:56dd5df33ab4 939 }
Helmut64 0:56dd5df33ab4 940
Helmut64 0:56dd5df33ab4 941 void OLEDDisplay::setFontTableLookupFunction(FontTableLookupFunction function) {
Helmut64 0:56dd5df33ab4 942 this->fontTableLookupFunction = function;
Helmut64 0:56dd5df33ab4 943 }
Helmut64 0:56dd5df33ab4 944
Helmut64 0:56dd5df33ab4 945
Helmut64 0:56dd5df33ab4 946 char DefaultFontTableLookup(const char ch) {
Helmut64 0:56dd5df33ab4 947 // UTF-8 to font table index converter
Helmut64 0:56dd5df33ab4 948 // Code form http://playground.arduino.cc/Main/Utf8ascii
Helmut64 0:56dd5df33ab4 949 static uint8_t LASTCHAR;
Helmut64 0:56dd5df33ab4 950
Helmut64 0:56dd5df33ab4 951 if (ch < 128) { // Standard ASCII-set 0..0x7F handling
Helmut64 0:56dd5df33ab4 952 LASTCHAR = 0;
Helmut64 0:56dd5df33ab4 953 return ch;
Helmut64 0:56dd5df33ab4 954 }
Helmut64 0:56dd5df33ab4 955
Helmut64 0:56dd5df33ab4 956 uint8_t last = LASTCHAR; // get last char
Helmut64 0:56dd5df33ab4 957 LASTCHAR = ch;
Helmut64 0:56dd5df33ab4 958
Helmut64 0:56dd5df33ab4 959 switch (last) { // conversion depnding on first UTF8-character
Helmut64 0:56dd5df33ab4 960 case 0xC2: return (uint8_t) ch;
Helmut64 0:56dd5df33ab4 961 case 0xC3: return (uint8_t) (ch | 0xC0);
Helmut64 0:56dd5df33ab4 962 case 0x82: if (ch == 0xAC) return (uint8_t) 0x80; // special case Euro-symbol
Helmut64 0:56dd5df33ab4 963 }
Helmut64 0:56dd5df33ab4 964
Helmut64 0:56dd5df33ab4 965 return (uint8_t) 0; // otherwise: return zero, if character has to be ignored
Helmut64 0:56dd5df33ab4 966 }
Helmut64 0:56dd5df33ab4 967