ThingPulse OLED SSD1306

Dependents:   Turtle_RadioShuttle

Committer:
Helmut Tschemernjak
Date:
Sun Apr 14 18:00:54 2019 +0200
Revision:
1:9270c15c6aea
Parent:
0:56dd5df33ab4
Child:
2:4ed55dfe5be7
Updated updated problem for single buffer operation

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