Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 6 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
[![Build Status](https://travis-ci.org/ThingPulse/esp8266-oled-ssd1306.svg?branch=master)](https://travis-ci.org/ThingPulse/esp8266-oled-ssd1306)

# ThingPulse ESP8266 OLED SSD1306
# ThingPulse OLED SSD1306 (ESP8266/ESP32/Mbed-OS)

> We just released version 4.0.0. Please have a look at our [upgrade guide](UPGRADE-4.0.md)

This is a driver for SSD1306 128x64 and 128x32 OLED displays running on the Arduino/ESP8266 platform.
This is a driver for SSD1306 128x64 and 128x32 OLED displays running on the Arduino/ESP8266 & ESP32 and mbed-os platforms.
Can be used with either the I2C or SPI version of the display.

You can either download this library as a zip file and unpack it to your Arduino/libraries folder or find it in the Arduino library manager under "ESP8266 and ESP32 Oled Driver for SSD1306 display".
You can either download this library as a zip file and unpack it to your Arduino/libraries folder or find it in the Arduino library manager under "ESP8266 and ESP32 Oled Driver for SSD1306 display". For mbed-os a copy of the files are available as an mbed-os library.

It is also available as a platformio library. Just execute the following command:
```
Expand All @@ -24,6 +24,9 @@ platformio lib install 562
This library has initially been written by Daniel Eichhorn (@squix78). Many thanks go to Fabrice Weinberg (@FWeinb) for optimizing and refactoring many aspects of the library. Also many thanks to the many committers who helped to add new features and who fixed many bugs.
The init sequence for the SSD1306 was inspired by Adafruit's library for the same display.

## mbed-os
This library has been adopted to support the ARM mbed-os environment. A copy of this library is available in mbed-os under the name OLED_SSD1306 by Helmut Tschemernjak. An alternate installation option is to copy the following files into your mbed-os project: OLEDDisplay.cpp OLEDDisplay.h OLEDDisplayFonts.h OLEDDisplayUi.cpp OLEDDisplayUi.h SSD1306I2C.h

## Usage

Check out the examples folder for a few comprehensive demonstrations how to use the library. Also check out the [ESP8266 Weather Station](https://github.com/ThingPulse/esp8266-weather-station) library which uses the OLED library to display beautiful weather information.
Expand Down
134 changes: 110 additions & 24 deletions src/OLEDDisplay.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
*
* Copyright (c) 2018 by ThingPulse, Daniel Eichhorn
* Copyright (c) 2018 by Fabrice Weinberg
* Copyright (c) 2019 by Helmut Tschemernjak - www.radioshuttle.de
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
Expand All @@ -28,20 +29,50 @@
*
*/

/*
* TODO Helmut
* - test/finish dislplay.printf() on mbed-os
* - Finish _putc with drawLogBuffer when running display
*/

#include "OLEDDisplay.h"

OLEDDisplay::OLEDDisplay() {

displayWidth = 128;
displayHeight = 64;
displayBufferSize = displayWidth * displayHeight / 8;
color = WHITE;
geometry = GEOMETRY_128_64;
textAlignment = TEXT_ALIGN_LEFT;
fontData = ArialMT_Plain_10;
fontTableLookupFunction = DefaultFontTableLookup;
buffer = NULL;
#ifdef OLEDDISPLAY_DOUBLE_BUFFER
buffer_back = NULL;
#endif
}

OLEDDisplay::~OLEDDisplay() {
end();
}

bool OLEDDisplay::init() {

logBufferSize = 0;
logBufferFilled = 0;
logBufferLine = 0;
logBufferMaxLines = 0;
logBuffer = NULL;

if (!this->connect()) {
DEBUG_OLEDDISPLAY("[OLEDDISPLAY][init] Can't establish connection to display\n");
return false;
}

if(this->buffer==NULL) {
this->buffer = (uint8_t*) malloc(sizeof(uint8_t) * displayBufferSize);
this->buffer = (uint8_t*) malloc((sizeof(uint8_t) * displayBufferSize) + getBufferOffset());
this->buffer += getBufferOffset();

if(!this->buffer) {
DEBUG_OLEDDISPLAY("[OLEDDISPLAY][init] Not enough memory to create display\n");
Expand All @@ -51,11 +82,12 @@ bool OLEDDisplay::init() {

#ifdef OLEDDISPLAY_DOUBLE_BUFFER
if(this->buffer_back==NULL) {
this->buffer_back = (uint8_t*) malloc(sizeof(uint8_t) * displayBufferSize);
this->buffer_back = (uint8_t*) malloc((sizeof(uint8_t) * displayBufferSize) + getBufferOffset());
this->buffer_back += getBufferOffset();

if(!this->buffer_back) {
DEBUG_OLEDDISPLAY("[OLEDDISPLAY][init] Not enough memory to create back buffer\n");
free(this->buffer);
free(this->buffer - getBufferOffset());
return false;
}
}
Expand All @@ -68,9 +100,9 @@ bool OLEDDisplay::init() {
}

void OLEDDisplay::end() {
if (this->buffer) { free(this->buffer); this->buffer = NULL; }
if (this->buffer) { free(this->buffer - getBufferOffset()); this->buffer = NULL; }
#ifdef OLEDDISPLAY_DOUBLE_BUFFER
if (this->buffer_back) { free(this->buffer_back); this->buffer_back = NULL; }
if (this->buffer_back) { free(this->buffer_back - getBufferOffset()); this->buffer_back = NULL; }
#endif
if (this->logBuffer != NULL) { free(this->logBuffer); this->logBuffer = NULL; }
}
Expand Down Expand Up @@ -405,8 +437,8 @@ void OLEDDisplay::drawStringInternal(int16_t xMove, int16_t yMove, char* text, u
uint8_t firstChar = pgm_read_byte(fontData + FIRST_CHAR_POS);
uint16_t sizeOfJumpTable = pgm_read_byte(fontData + CHAR_NUM_POS) * JUMPTABLE_BYTES;

uint8_t cursorX = 0;
uint8_t cursorY = 0;
uint16_t cursorX = 0;
uint16_t cursorY = 0;

switch (textAlignment) {
case TEXT_ALIGN_CENTER_BOTH:
Expand All @@ -430,15 +462,15 @@ void OLEDDisplay::drawStringInternal(int16_t xMove, int16_t yMove, char* text, u
int16_t xPos = xMove + cursorX;
int16_t yPos = yMove + cursorY;

byte code = text[j];
uint8_t code = text[j];
if (code >= firstChar) {
byte charCode = code - firstChar;
uint8_t charCode = code - firstChar;

// 4 Bytes per char code
byte msbJumpToChar = pgm_read_byte( fontData + JUMPTABLE_START + charCode * JUMPTABLE_BYTES ); // MSB \ JumpAddress
byte lsbJumpToChar = pgm_read_byte( fontData + JUMPTABLE_START + charCode * JUMPTABLE_BYTES + JUMPTABLE_LSB); // LSB /
byte charByteSize = pgm_read_byte( fontData + JUMPTABLE_START + charCode * JUMPTABLE_BYTES + JUMPTABLE_SIZE); // Size
byte currentCharWidth = pgm_read_byte( fontData + JUMPTABLE_START + charCode * JUMPTABLE_BYTES + JUMPTABLE_WIDTH); // Width
uint8_t msbJumpToChar = pgm_read_byte( fontData + JUMPTABLE_START + charCode * JUMPTABLE_BYTES ); // MSB \ JumpAddress
uint8_t lsbJumpToChar = pgm_read_byte( fontData + JUMPTABLE_START + charCode * JUMPTABLE_BYTES + JUMPTABLE_LSB); // LSB /
uint8_t charByteSize = pgm_read_byte( fontData + JUMPTABLE_START + charCode * JUMPTABLE_BYTES + JUMPTABLE_SIZE); // Size
uint8_t currentCharWidth = pgm_read_byte( fontData + JUMPTABLE_START + charCode * JUMPTABLE_BYTES + JUMPTABLE_WIDTH); // Width

// Test if the char is drawable
if (!(msbJumpToChar == 255 && lsbJumpToChar == 255)) {
Expand Down Expand Up @@ -745,20 +777,50 @@ size_t OLEDDisplay::write(const char* str) {
return length;
}

#ifdef __MBED__
int OLEDDisplay::_putc(int c) {

if (!fontData)
return 1;
if (!logBufferSize) {
uint8_t textHeight = pgm_read_byte(fontData + HEIGHT_POS);
uint16_t lines = this->displayHeight / textHeight;
uint16_t chars = 2 * (this->displayWidth / textHeight);

if (this->displayHeight % textHeight)
lines++;
if (this->displayWidth % textHeight)
chars++;
setLogBuffer(lines, chars);
}

return this->write((uint8_t)c);
}
#endif

// Private functions
void OLEDDisplay::setGeometry(OLEDDISPLAY_GEOMETRY g) {
void OLEDDisplay::setGeometry(OLEDDISPLAY_GEOMETRY g, uint16_t width, uint16_t height) {
this->geometry = g;
if (g == GEOMETRY_128_64) {
this->displayWidth = 128;
this->displayHeight = 64;
} else if (g == GEOMETRY_128_32) {
this->displayWidth = 128;
this->displayHeight = 32;
}
this->displayBufferSize = displayWidth*displayHeight/8;
switch (g) {
case GEOMETRY_128_64:
this->displayWidth = 128;
this->displayHeight = 64;
break;
case GEOMETRY_128_32:
this->displayWidth = 128;
this->displayHeight = 32;
break;
case GEOMETRY_RAWMODE:
this->displayWidth = width > 0 ? width : 128;
this->displayHeight = height > 0 ? height : 64;
break;
}
this->displayBufferSize = displayWidth * displayHeight /8;
}

void OLEDDisplay::sendInitCommands(void) {
if (geometry == GEOMETRY_RAWMODE)
return;
sendCommand(DISPLAYOFF);
sendCommand(SETDISPLAYCLOCKDIV);
sendCommand(0xF0); // Increase speed of the display max ~96Hz
Expand Down Expand Up @@ -821,7 +883,7 @@ void inline OLEDDisplay::drawInternal(int16_t xMove, int16_t yMove, int16_t widt
yOffset = initYOffset;
}

byte currentByte = pgm_read_byte(data + offset + i);
uint8_t currentByte = pgm_read_byte(data + offset + i);

int16_t xPos = xMove + (i / rasterHeight);
int16_t yPos = ((yMove >> 3) + (i % rasterHeight)) * this->width();
Expand Down Expand Up @@ -862,8 +924,9 @@ void inline OLEDDisplay::drawInternal(int16_t xMove, int16_t yMove, int16_t widt
// and setting the new yOffset
yOffset = 8 - yOffset;
}

#ifndef __MBED__
yield();
#endif
}
}
}
Expand Down Expand Up @@ -899,3 +962,26 @@ char* OLEDDisplay::utf8ascii(String str) {
void OLEDDisplay::setFontTableLookupFunction(FontTableLookupFunction function) {
this->fontTableLookupFunction = function;
}


char DefaultFontTableLookup(const uint8_t ch) {
// UTF-8 to font table index converter
// Code form http://playground.arduino.cc/Main/Utf8ascii
static uint8_t LASTCHAR;

if (ch < 128) { // Standard ASCII-set 0..0x7F handling
LASTCHAR = 0;
return ch;
}

uint8_t last = LASTCHAR; // get last char
LASTCHAR = ch;

switch (last) { // conversion depnding on first UTF8-character
case 0xC2: return (uint8_t) ch;
case 0xC3: return (uint8_t) (ch | 0xC0);
case 0x82: if (ch == 0xAC) return (uint8_t) 0x80; // special case Euro-symbol
}

return (uint8_t) 0; // otherwise: return zero, if character has to be ignored
}
Loading