Full Code of squix78/esp8266-oled-ssd1306 for AI

master 5fd04d4bc6c4 cached
48 files
377.1 KB
191.5k tokens
54 symbols
1 requests
Download .txt
Showing preview only (395K chars total). Download the full file or copy to clipboard to get everything.
Repository: squix78/esp8266-oled-ssd1306
Branch: master
Commit: 5fd04d4bc6c4
Files: 48
Total size: 377.1 KB

Directory structure:
gitextract_do6gekij/

├── .editorconfig
├── .github/
│   ├── ISSUE_TEMPLATE/
│   │   ├── bug_report.md
│   │   └── support-request.md
│   ├── stale.yml
│   └── workflows/
│       └── main.yml
├── .gitignore
├── CMakeLists.txt
├── CONTRIBUTING.md
├── README.md
├── README_GEOMETRY_64_48.md
├── UPGRADE-3.0.md
├── UPGRADE-4.0.md
├── component.mk
├── examples/
│   ├── SSD1306ClockDemo/
│   │   ├── SSD1306ClockDemo.ino
│   │   └── images.h
│   ├── SSD1306DrawingDemo/
│   │   └── SSD1306DrawingDemo.ino
│   ├── SSD1306FontTryout/
│   │   ├── Dialog_plain_6.h
│   │   ├── Dialog_plain_7.h
│   │   ├── Dialog_plain_8.h
│   │   └── SSD1306FontTryout.ino
│   ├── SSD1306OTADemo/
│   │   └── SSD1306OTADemo.ino
│   ├── SSD1306ScrollVerticalDemo/
│   │   └── SSD1306ScrollVerticalDemo.ino
│   ├── SSD1306SimpleDemo/
│   │   ├── SSD1306SimpleDemo.ino
│   │   └── images.h
│   ├── SSD1306TwoScreenDemo/
│   │   ├── SSD1306TwoScreenDemo.ino
│   │   └── images.h
│   └── SSD1306UiDemo/
│       ├── SSD1306UiDemo.ino
│       └── images.h
├── keywords.txt
├── library.json
├── library.properties
├── license
├── platformio.ini
├── resources/
│   └── glyphEditor.html
└── src/
    ├── OLEDDisplay.cpp
    ├── OLEDDisplay.h
    ├── OLEDDisplayFonts.h
    ├── OLEDDisplayUi.cpp
    ├── OLEDDisplayUi.h
    ├── SH1106.h
    ├── SH1106Brzo.h
    ├── SH1106Spi.h
    ├── SH1106Wire.h
    ├── SSD1306.h
    ├── SSD1306Brzo.h
    ├── SSD1306I2C.h
    ├── SSD1306Spi.h
    └── SSD1306Wire.h

================================================
FILE CONTENTS
================================================

================================================
FILE: .editorconfig
================================================
# This file is for unifying the coding style for different editors and IDEs
# editorconfig.org

root = true

[*]
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
indent_style = space
indent_size = 2
max_line_length = 120
curly_bracket_next_line = false


================================================
FILE: .github/ISSUE_TEMPLATE/bug_report.md
================================================
---
name: Bug report
about: Create a report to help us improve
title: ''
labels: ''
assignees: ''

---

**Describe the bug**
A clear and concise description of what the bug is.

**To Reproduce**
Steps to reproduce the behavior:
1. Go to '...'
2. Do this '....'
3. Do that '....'
4. See error

**Sample code**
Provide a [MCVE](https://stackoverflow.com/help/minimal-reproducible-example) below.
```c
# your code goes here
```

**Expected behavior**
A clear and concise description of what you expected to happen.

**Screenshots**
If applicable, add screenshots to help explain your problem.

**Versions (please complete the following information):**
 - Library: [e.g. 4.2]
 - Platform [e.g. ESP266 Arduino Core 2.5.x]

**Additional context**
Add any other context about the problem here.


================================================
FILE: .github/ISSUE_TEMPLATE/support-request.md
================================================
---
name: Support request
about: Describe this issue template's purpose here.
title: ''
labels: ''
assignees: ''

---

We offer support to our customers at https://support.thingpulse.com/. Send us an email if you don't have an account yet.


================================================
FILE: .github/stale.yml
================================================
# Number of days of inactivity before an issue becomes stale
daysUntilStale: 180
# Number of days of inactivity before a stale issue is closed
daysUntilClose: 14
# Issues with these labels will never be considered stale
exemptLabels:
  - pinned
  - security
# Label to use when marking an issue as stale
staleLabel: stale
# Comment to post when marking an issue as stale. Set to `false` to disable
markComment: >
  This issue has been automatically marked as stale because it has not had
  recent activity. It will be closed if no further activity occurs. Thank you
  for your contributions.
# Comment to post when closing a stale issue. Set to `false` to disable
closeComment: false


================================================
FILE: .github/workflows/main.yml
================================================
# documentation at https://docs.platformio.org/en/latest/integration/ci/github-actions.html

name: PlatformIO CI

on: [push, pull_request]

jobs:
  build:

    runs-on: ubuntu-latest
    strategy:
      matrix:
        example: [examples/SSD1306UiDemo, examples/SSD1306SimpleDemo, examples/SSD1306DrawingDemo, examples/SSD1306OTADemo, examples/SSD1306ClockDemo, examples/SSD1306TwoScreenDemo]

    steps:
    - uses: actions/checkout@v4
    - name: Cache pip
      uses: actions/cache@v3
      with:
        path: ~/.cache/pip
        key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}
        restore-keys: ${{ runner.os }}-pip-
    - name: Cache PlatformIO
      uses: actions/cache@v3
      with:
        path: ~/.platformio
        key: ${{ runner.os }}-${{ hashFiles('**/lockfiles') }}
    - name: Set up Python
      uses: actions/setup-python@v5
    - name: Install PlatformIO
      run: |
        python -m pip install --upgrade pip
        pip install --upgrade platformio intelhex
    - name: Install library dependencies
      run: pio pkg install -g -l "paulstoffregen/Time@^1.6"
    - name: Run PlatformIO
      run: pio ci --lib="." --board=nodemcuv2 --board=d1_mini --board=esp-wrover-kit --board=esp32doit-devkit-v1
      env:
        PLATFORMIO_CI_SRC: ${{ matrix.example }}


================================================
FILE: .gitignore
================================================
.vscode
.pio


================================================
FILE: CMakeLists.txt
================================================
set(COMPONENT_ADD_INCLUDEDIRS src)
set(COMPONENT_PRIV_REQUIRES arduino-esp32)
set(COMPONENT_SRCDIRS src)
register_component()


================================================
FILE: CONTRIBUTING.md
================================================
# Contributing to ThingPulse OLED SSD1306

:+1::tada: First off, thanks for taking the time to contribute! :tada::+1:

The following is a set of guidelines for contributing to the ThingPulse OLED SSD1306 library on GitHub. These are just guidelines, not rules, use your best judgment and feel free to propose changes to this document in a pull request.

It is appreciated if you raise an issue _before_ you start changing the code, discussing the proposed change; emphasizing that you are proposing to develop the patch yourself, and outlining the strategy for implementation. This type of discussion is what we should be doing on the issues list and it is better to do this before or in parallel to developing the patch rather than having "you should have done it this way" type of feedback on the PR itself.

### Table Of Contents
* [General remarks](#general-remarks)
* [Writing Documentation](#writing-documentation)
* [Working with Git and GitHub](#working-with-git-and-github)
  * [General flow](#general-flow)
  * [Keeping your fork in sync](#keeping-your-fork-in-sync)
  * [Commit messages](#commit-messages)

## General remarks
We are a friendly and welcoming community and look forward to your contributions. Once your contribution is integrated into this repository we feel responsible for it. Therefore, be prepared for constructive feedback. Before we merge anything we need to ensure that it fits in and is consistent with the rest of code.
If you made something really cool but won't spend the time to integrate it into this upstream project please still share it in your fork on GitHub. If you mention it in an issue we'll take a look at it anyway.

## Writing Documentation
ThingPulse maintains documentation for its products at [https://github.com/thingpulse/docs/](https://github.com/thingpulse/docs/). If you contribute features for this project that require altering the respective product guide then we ask you to prepare a pull request with the necessary documentation changes as well.

## Working with Git and GitHub

Avoid intermediate merge commits. [Rebase](https://www.atlassian.com/git/tutorials/merging-vs-rebasing) your feature branch onto `master` to pull updates and verify your local changes against them before placing the pull request.

### General flow
1. [Fork](https://help.github.com/articles/fork-a-repo) this repository on GitHub.
1. [Create a branch](https://help.github.com/articles/creating-and-deleting-branches-within-your-repository/#creating-a-branch) in your fork on GitHub **based on the `master` branch**.
1. Clone the fork on your machine with `git clone https://github.com/<your-account>/<esp8266-oled-ssd1306>.git`
1. `cd <weather-station-fork>` then run `git remote add upstream https://github.com/ThingPulse/esp8266-oled-ssd1306`
1. `git checkout <branch-name>`
1. Make changes to the code base and commit them using e.g. `git commit -a -m 'Look ma, I did it'`
1. When you're done bring your fork up-to-date with the upstream repo ([see below](#keeping-your-fork-in-sync)). Then rebase your branch on `master` running `git rebase master`.
1. `git push`
1. [Create a pull request](https://help.github.com/articles/creating-a-pull-request/) (PR) on GitHub.

This is just one way of doing things. If you're proficient in Git matters you're free to choose your own. If you want to read more then the [GitHub chapter in the Git book](http://git-scm.com/book/en/v2/GitHub-Contributing-to-a-Project#The-GitHub-Flow) is a way to start. [GitHub's own documentation](https://help.github.com/categories/collaborating/) contains a wealth of information as well.

### Keeping your fork in sync
You need to sync your fork with the upstream repository from time to time, latest before you rebase (see flow above).

1. `git fetch upstream`
1. `git checkout master`
1. `git merge upstream/master`

### Commit messages

From: [http://git-scm.com/book/ch5-2.html](http://git-scm.com/book/ch5-2.html)
<pre>
Short (50 chars or less) summary of changes

More detailed explanatory text, if necessary.  Wrap it to about 72
characters or so.  In some contexts, the first line is treated as the
subject of an email and the rest of the text as the body.  The blank
line separating the summary from the body is critical (unless you omit
the body entirely); tools like rebase can get confused if you run the
two together.

Further paragraphs come after blank lines.

- Bullet points are okay, too
- Typically a hyphen or asterisk is used for the bullet, preceded by a
   single space, with blank lines in between, but conventions vary here
</pre>

Don't forget to [reference affected issues](https://help.github.com/articles/closing-issues-via-commit-messages/) in the commit message to have them closed automatically on GitHub.

[Amend](https://help.github.com/articles/changing-a-commit-message/) your commit messages if necessary to make sure what the world sees on GitHub is as expressive and meaningful as possible.


================================================
FILE: README.md
================================================
# ThingPulse OLED SSD1306 (ESP8266/ESP32/Mbed-OS)

[![PlatformIO Registry](https://badges.registry.platformio.org/packages/thingpulse/library/ESP8266%20and%20ESP32%20OLED%20driver%20for%20SSD1306%20displays.svg)](https://registry.platformio.org/libraries/thingpulse/ESP8266%20and%20ESP32%20OLED%20driver%20for%20SSD1306%20displays)
[![Build Status](https://github.com/ThingPulse/esp8266-oled-ssd1306/actions/workflows/main.yml/badge.svg)](https://github.com/ThingPulse/esp8266-oled-ssd1306/actions)

This is a driver for SSD1306 and SH1106 128x64, 128x32, 64x48 and 64x32 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.

This library drives the OLED display included in the [ThingPulse IoT starter kit](https://thingpulse.com/product/esp8266-iot-electronics-starter-kit-weatherstation-planespotter-worldclock/) aka classic kit aka weather station kit.

[![ThingPulse ESP8266 WeatherStation Classic Kit](https://github.com/ThingPulse/esp8266-weather-station/blob/master/resources/ThingPulse-ESP8266-Weather-Station.jpeg?raw=true)](https://thingpulse.com/product/esp8266-iot-electronics-starter-kit-weatherstation-planespotter-worldclock/)

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](https://platformio.org/lib/show/2978/ESP8266%20and%20ESP32%20OLED%20driver%20for%20SSD1306%20displays/examples). Just execute the following command:
```
platformio lib install 2978
```

## Service level promise

<table><tr><td><img src="https://thingpulse.com/assets/ThingPulse-open-source-prime.png" width="150">
</td><td>This is a ThingPulse <em>prime</em> project. See our <a href="https://thingpulse.com/about/open-source-commitment/">open-source commitment declaration</a> for what this means.</td></tr></table>

## Credits

This library has initially been written by [Daniel Eichhorn](https://github.com/squix78). Many thanks go to [Fabrice Weinberg](https://github.com/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. Mbed-OS support and other improvements were contributed by [Helmut Tschemernjak](https://github.com/helmut64).

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.

## Upgrade

The API changed a lot with the 3.0 release. If you were using this library with older versions please have a look at the [Upgrade Guide](UPGRADE-3.0.md).

Going from 3.x version to 4.0 a lot of internals changed and compatibility for more displays was added. Please read the [Upgrade Guide](UPGRADE-4.0.md).

## Features

* Draw pixels at given coordinates
* Draw lines from given coordinates to given coordinates
* Draw or fill a rectangle with given dimensions
* Draw Text at given coordinates:
 * Define Alignment: Left, Right and Center
 * Set the Fontface you want to use (see section Fonts below)
 * Limit the width of the text by an amount of pixels. Before this widths will be reached, the renderer will wrap the text to a new line if possible
* Display content in automatically side scrolling carousel
 * Define transition cycles
 * Define how long one frame will be displayed
 * Draw the different frames in callback methods
 * One indicator per frame will be automatically displayed. The active frame will be displayed from inactive once

## Fonts

Fonts are defined in a proprietary but open format. You can create new font files by choosing from a given list
of open sourced Fonts from this web app: http://oleddisplay.squix.ch
Choose the font family, style and size, check the preview image and if you like what you see click the "Create" button. This will create the font array in a text area form where you can copy and paste it into a new or existing header file.


![FontTool](https://github.com/squix78/esp8266-oled-ssd1306/raw/master/resources/FontTool.png)

## Hardware Abstraction

The library supports different protocols to access the OLED display. Currently there is support for I2C using the built in Wire.h library, I2C by using the much faster [BRZO I2C library](https://github.com/pasko-zh/brzo_i2c) written in assembler and it also supports displays which come with the SPI interface.

### I2C with Wire.h

```C++
#include <Wire.h>
#include "SSD1306Wire.h"

// for 128x64 displays:
SSD1306Wire display(0x3c, SDA, SCL);  // ADDRESS, SDA, SCL
// for 128x32 displays:
// SSD1306Wire display(0x3c, SDA, SCL, GEOMETRY_128_32);  // ADDRESS, SDA, SCL, GEOMETRY_128_32 (or 128_64)
// for using 2nd Hardware I2C (if available)
// SSD1306Wire(0x3c, SDA, SCL, GEOMETRY_128_64, I2C_TWO); //default value is I2C_ONE if not mentioned
// By default SD1306Wire set I2C frequency to 700000, you can use set either another frequency or skip setting the frequency by providing -1 value
// SSD1306Wire(0x3c, SDA, SCL, GEOMETRY_128_64, I2C_ONE, 400000); //set I2C frequency to 400kHz
// SSD1306Wire(0x3c, SDA, SCL, GEOMETRY_128_64, I2C_ONE, -1); //skip setting the I2C bus frequency
```

for a SH1106:
```C++
#include <Wire.h>
#include "SH1106Wire.h"

SH1106Wire display(0x3c, SDA, SCL);  // ADDRESS, SDA, SCL
// By default SH1106Wire set I2C frequency to 700000, you can use set either another frequency or skip setting the frequency by providing -1 value
// SH1106Wire(0x3c, SDA, SCL, GEOMETRY_128_64, I2C_ONE, 400000); //set I2C frequency to 400kHz
// SH1106Wire(0x3c, SDA, SCL, GEOMETRY_128_64, I2C_ONE, -1); //skip setting the I2C bus frequency
```

### I2C with brzo_i2c

```C++
#include <brzo_i2c.h>
#include "SSD1306Brzo.h"

SSD1306Brzo display(0x3c, SDA, SCL);  // ADDRESS, SDA, SCL
```
or for the SH1106:
```C++
#include <brzo_i2c.h>
#include "SH1106Brzo.h"

SH1106Brzo display(0x3c, SDA, SCL);  // ADDRESS, SDA, SCL
```

### SPI

```C++
#include <SPI.h>
#include "SSD1306Spi.h"

SSD1306Spi display(D0, D2, D8);  // RES, DC, CS
```
or for the SH1106:
```C++
#include <SPI.h>
#include "SH1106Spi.h"

SH1106Spi display(D0, D2, CS);  // RES, DC, CS
```

In case the CS pin is not used (hard wired to ground), pass CS as -1.

## API

### Display Control

```C++
// Initialize the display
void init();

// Free the memory used by the display
void end();

// Cycle through the initialization
void resetDisplay(void);

// Connect again to the display through I2C
void reconnect(void);

// Turn the display on
void displayOn(void);

// Turn the display offs
void displayOff(void);

// Clear the local pixel buffer
void clear(void);

// Write the buffer to the display memory
void display(void);

// Inverted display mode
void invertDisplay(void);

// Normal display mode
void normalDisplay(void);

// Set display contrast
// really low brightness & contrast: contrast = 10, precharge = 5, comdetect = 0
// normal brightness & contrast:  contrast = 100
void setContrast(uint8_t contrast, uint8_t precharge = 241, uint8_t comdetect = 64);

// Convenience method to access setContrast with only brightness parameter
void setBrightness(uint8_t);

// Turn the display upside down
void flipScreenVertically();

// Draw the screen mirrored
void mirrorScreen();
```

## Pixel drawing

```C++

/* Drawing functions */
// Sets the color of all pixel operations
// color : BLACK, WHITE, INVERSE
void setColor(OLEDDISPLAY_COLOR color);

// Draw a pixel at given position
void setPixel(int16_t x, int16_t y);

// Draw a line from position 0 to position 1
void drawLine(int16_t x0, int16_t y0, int16_t x1, int16_t y1);

// Draw the border of a rectangle at the given location
void drawRect(int16_t x, int16_t y, int16_t width, int16_t height);

// Fill the rectangle
void fillRect(int16_t x, int16_t y, int16_t width, int16_t height);

// Draw the border of a circle
void drawCircle(int16_t x, int16_t y, int16_t radius);

// Fill circle
void fillCircle(int16_t x, int16_t y, int16_t radius);

// Draw an empty triangle i.e. only the outline
void drawTriangle(int16_t x0, int16_t y0, int16_t x1, int16_t y1, int16_t x2, int16_t y2);

// Draw a solid triangle i.e. filled
void fillTriangle(int16_t x0, int16_t y0, int16_t x1, int16_t y1, int16_t x2, int16_t y2);

// Draw a line horizontally
void drawHorizontalLine(int16_t x, int16_t y, int16_t length);

// Draw a lin vertically
void drawVerticalLine(int16_t x, int16_t y, int16_t length);

// Draws a rounded progress bar with the outer dimensions given by width and height. Progress is
// a unsigned byte value between 0 and 100
void drawProgressBar(uint16_t x, uint16_t y, uint16_t width, uint16_t height, uint8_t progress);

// Draw a bitmap in the internal image format
void drawFastImage(int16_t x, int16_t y, int16_t width, int16_t height, const uint8_t *image);

// Draw a XBM
void drawXbm(int16_t x, int16_t y, int16_t width, int16_t height, const uint8_t *xbm);
```

## Text operations

``` C++
// Draws a string at the given location, returns how many chars have been written
uint16_t drawString(int16_t x, int16_t y, const String &text);

// Draws a String with a maximum width at the given location.
// If the given String is wider than the specified width
// The text will be wrapped to the next line at a space or dash
// returns 0 if everything fits on the screen or the numbers of characters in the
// first line if not
uint16_t drawStringMaxWidth(int16_t x, int16_t y, uint16_t maxLineWidth, const String &text);

// Returns the width of the const char* with the current
// font settings
uint16_t getStringWidth(const char* text, uint16_t length, bool utf8 = false);

// Convencience method for the const char version
uint16_t getStringWidth(const String &text);

// Specifies relative to which anchor point
// the text is rendered. Available constants:
// TEXT_ALIGN_LEFT, TEXT_ALIGN_CENTER, TEXT_ALIGN_RIGHT, TEXT_ALIGN_CENTER_BOTH
void setTextAlignment(OLEDDISPLAY_TEXT_ALIGNMENT textAlignment);

// Sets the current font. Available default fonts
// ArialMT_Plain_10, ArialMT_Plain_16, ArialMT_Plain_24
// Or create one with the font tool at http://oleddisplay.squix.ch
void setFont(const uint8_t* fontData);
```

## Arduino `Print` functionality

Because this class has been "derived" from Arduino's `Print` class, you can use the functions it provides. In plain language, this means that you can use `print`, `println` and `printf` to the display. Internally, a buffer holds the text that was printed to the display previously (that would still fit on the display) and every time you print something, this buffer is put on the screen, using the functions from the previous section.

What that means is that printing using `print` and "manually" putting things on the display are somewhat mutually exclusive: as soon as you print, everything that was on the display already is gone and only what you put there before with `print`, `println` or `printf` remains. Still, using `print` is a very simple way to put something on the display quickly.

One extra function is provided: `cls()`
```cpp
// cls() will clear the display immediately and empty the logBuffer, meaning
// the next print statement will print at the top of the display again.
// cls() should not be confused with clear(), which only clears the internal
// graphics buffer, which can then be shown on the display with display().
void cls();

> _Note that printing to the display, contrary to what you might expect, does not wrap your lines, so everything on a line that doesn't fit on the screen is cut off._
```

&nbsp;

<hr>

## Ui Library (OLEDDisplayUi)

The Ui Library is used to provide a basic set of user interface elements called `Frames` and `Overlays`. A `Frame` is used to provide
information to the user. The default behaviour is to display a `Frame` for a defined time and than move to the next `Frame`. The library also
provides an `Indicator` element that will be updated accordingly. An `Overlay` on the other hand is a piece of information (e.g. a clock) that
is always displayed at the same position.

```C++
/**
 * Initialise the display
 */
void init();

/**
 * Configure the internal used target FPS
 */
void setTargetFPS(uint8_t fps);

/**
 * Enable automatic transition to next frame after the some time can be configured with
 * `setTimePerFrame` and `setTimePerTransition`.
 */
void enableAutoTransition();

/**
 * Disable automatic transition to next frame.
 */
void disableAutoTransition();

/**
 * Set the direction if the automatic transitioning
 */
void setAutoTransitionForwards();
void setAutoTransitionBackwards();

/**
 *  Set the approx. time a frame is displayed
 */
void setTimePerFrame(uint16_t time);

/**
 * Set the approx. time a transition will take
 */
void setTimePerTransition(uint16_t time);

/**
 * Draw the indicator.
 * This is the default state for all frames if
 * the indicator was hidden on the previous frame
 * it will be slided in.
 */
void enableIndicator();

/**
 * Don't draw the indicator.
 * This will slide out the indicator
 * when transitioning to the next frame.
 */
void disableIndicator();

/**
 * Enable drawing of all indicators.
 */
void enableAllIndicators();

/**
 * Disable drawing of all indicators.
 */
void disableAllIndicators();

/**
 * Set the position of the indicator bar.
 */
void setIndicatorPosition(IndicatorPosition pos);

/**
 * Set the direction of the indicator bar. Defining the order of frames ASCENDING / DESCENDING
 */
void setIndicatorDirection(IndicatorDirection dir);

/**
 * Set the symbol to indicate an active frame in the indicator bar.
 */
void setActiveSymbol(const uint8_t* symbol);

/**
 * Set the symbol to indicate an inactive frame in the indicator bar.
 */
void setInactiveSymbol(const uint8_t* symbol);

/**
 * Configure what animation is used to transition from one frame to another
 */
void setFrameAnimation(AnimationDirection dir);

/**
 * Add frame drawing functions
 */
void setFrames(FrameCallback* frameFunctions, uint8_t frameCount);

/**
 * Add overlays drawing functions that are draw independent of the Frames
 */
void setOverlays(OverlayCallback* overlayFunctions, uint8_t overlayCount);

/**
 * Set the function that will draw each step
 * in the loading animation
 */
void setLoadingDrawFunction(LoadingDrawFunction loadingDrawFunction);

/**
 * Run the loading process
 */
void runLoadingProcess(LoadingStage* stages, uint8_t stagesCount);

// Manual control
void nextFrame();
void previousFrame();

/**
 * Switch without transition to frame `frame`.
 */
void switchToFrame(uint8_t frame);

/**
 * Transition to frame `frame`. When the `frame` number is bigger than the current
 * frame the forward animation will be used, otherwise the backwards animation is used.
 */
void transitionToFrame(uint8_t frame);

// State Info
OLEDDisplayUiState* getUiState();

// This needs to be called in the main loop
// the returned value is the remaining time (in ms)
// you have to draw after drawing to keep the frame budget.
int8_t update();
```

## Creating and using XBM bitmaps

If you want to display your own images with this library, the best way to do this is using a bitmap.

There are two options to convert an image to a compatible bitmap:
1. **Using Gimp.**
   In this case exporting the bitmap in an 1-bit XBM format is sufficient.
2. **Using a converter website.**
   You could also use online converter services like e.g. [https://javl.github.io/image2cpp/](https://javl.github.io/image2cpp/). The uploaded image should have the same dimension as the screen (e.g. 128x64). The following output settings should be set:
    - Draw Mode: Horizontal - 1 bit per pixel
    - Swap bits in byte: swap checkbox should be checked.

The resulting bitmap can be put into a header file:
```C++
const unsigned char epd_example [] PROGMEM = {
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ... 
    ...
};
```

Subsequently, it can be used like this:
```C++
display.clear();
display.drawXbm(0, 0, 128, 64, epd_example); // assuming your bitmap is 128x64
display.display();
```

## Example: SSD1306Demo

### Frame 1
![DemoFrame1](https://github.com/squix78/esp8266-oled-ssd1306/raw/master/resources/DemoFrame1.jpg)

This frame shows three things:
 * How to draw an XMB image
 * How to draw static text which is not moved by the frame transition
 * The active/inactive frame indicators

### Frame 2
![DemoFrame2](https://github.com/squix78/esp8266-oled-ssd1306/raw/master/resources/DemoFrame2.jpg)

Currently there are one fontface with three sizes included in the library: Arial 10, 16 and 24. Once the converter is published you will be able to convert any ttf font into the used format.

### Frame 3

![DemoFrame3](https://github.com/squix78/esp8266-oled-ssd1306/raw/master/resources/DemoFrame3.jpg)

This frame demonstrates the text alignment. The coordinates in the frame show relative to which position the texts have been rendered.

### Frame 4

![DemoFrame4](https://github.com/squix78/esp8266-oled-ssd1306/raw/master/resources/DemoFrame4.jpg)

This shows how to use define a maximum width after which the driver automatically wraps a word to the next line. This comes in very handy if you have longer texts to display.

### SPI version

![SPIVersion](https://github.com/neptune2/esp8266-oled-ssd1306/raw/master/resources/SPI_version.jpg)

This shows the code working on the SPI version of the display. See demo code for ESP8266 pins used.

## Selection of projects using this library

 * [QRCode ESP8266](https://github.com/anunpanya/ESP8266_QRcode) (by @anunpanya)
 * [Scan I2C](https://github.com/hallard/Scan-I2C-WiFi) (by @hallard)
 * [ThingPulse Weather Station](https://github.com/ThingPulse/esp8266-weather-station)
 * [Meshtastic](https://www.meshtastic.org/) - an open source GPS communicator mesh radio
 * [OpenMQTTGateway](https://docs.openmqttgateway.com) - OpenMQTTGateway aims to unify various technologies and protocols into a single firmware. This reduces the need for multiple physical bridges and streamlines diverse technologies under the widely-used MQTT protocol.
 * [OpenAstroTracker](https://openastrotech.com) - Open source hardware and software for Astrophotography. The firmware for the mounts supports displays and uses this library to drive them.
 * Yours?


================================================
FILE: README_GEOMETRY_64_48.md
================================================
# GEOMETRY_64_48

The 64x48 geometry setting are working with the `Wire.h` and `brzo_i2c` libraries.

I've tested it successfully with a WEMOS D1 mini Lite and a WEMOS OLED shield

Initialization code:

- Wire
```
#include <Wire.h>
#include <SSD1306Wire.h>
SSD1306Wire display(0x3c, D2, D1, GEOMETRY_64_48 ); // WEMOS OLED shield
```

- BRZO i2c
```
#include <SSD1306Brzo.h>
SSD1306Brzo display(0x3c, D2, D1, GEOMETRY_64_48 ); // WEMOS OLED Shield
```


================================================
FILE: UPGRADE-3.0.md
================================================
# Upgrade from 2.0 to 3.0

While developing version 3.0 we made some breaking changes to the public
API of this library. This document will help you update your code to work with
version 3.0

## Font Definitions

To get better performance and a smaller font definition format, we change the memory
layout of the font definition format. If you are using custom fonts not included in
this library we updated the font generator [here](http://oleddisplay.squix.ch/#/home).
Please update your fonts to be working with 3.0 by selecting the respective version in the dropdown.


## Architectural Changes

To become a more versatile library for the SSD1306 chipset we abstracted the
hardware connection into subclasses of the base display class now called `OLEDDisplay`.
This library is currently shipping with three implementations:

  * `SSD1306Wire` implementing the I2C protocol using the Wire Library.    
  * `SSD1306Brzo` implementing the I2C protocol using the faster [`brzo_i2c`](https://github.com/pasko-zh/brzo_i2c) library.
  * `SSD1306Spi` implementing the SPI protocol.

To keep backwards compatiblity with the old API `SSD1306` is an alias of `SSD1306Wire`.
If you are not using the UI components you don't have to change anything to keep your code working.

## Name Changes

[Naming things is hard](http://martinfowler.com/bliki/TwoHardThings.html), to better reflect our intention with this library
we changed the name of the base class to `OLEDDisplay` and the UI library accordingly to `OLEDDisplayUi`.
As a consequence the type definitions of all frame and overlay related functions changed.
This means that you have to update all your frame drawing callbacks from:

```c
bool frame1(SSD1306 *display,  SSD1306UiState* state, int x, int y);
```

too

```c
void frame1(OLEDDisplay *display,  OLEDDisplayUiState* state, int16_t x, int16_t y);
```

And your overlay drawing functions from:

```c
bool overlay1(SSD1306 *display,  SSD1306UiState* state);
```

too

```c
void overlay1(OLEDDisplay *display,  OLEDDisplayUiState* state);
```

## New Features

### Loading Animation

While using this library ourself we noticed a pattern emerging. We want to drawing
a loading progress while connecting to WiFi and updating weather data etc.

The simplest thing was to add the function `drawProgressBar(x, y, width,  height, progress)`
,where `progress` is between `0` and `100`, right to the `OLEDDisplay` class.

But we didn't stop there. We added a new feature to the `OLEDDisplayUi` called `LoadingStages`.
You can define your loading process like this:

```c++
LoadingStage loadingStages[] = {
  {
    .process = "Connect to WiFi",
    .callback = []() {
      // Connect to WiFi
    }
  },
  {
    .process = "Get time from NTP",
    .callback = []() {
      // Get current time via NTP
    }
  }
  // more steps
};

int LOADING_STAGES_COUNT = sizeof(loadingStages) / sizeof(LoadingStage);
```

After defining your array of `LoadingStages` you can then run the loading process by using
`ui.runLoadingProcess(loadingStages, LOADING_STAGES_COUNT)`. This will give you a
nice little loading animation you can see in the beginning of [this](https://vimeo.com/168362918)
video.

To further customize this you are free to define your own `LoadingDrawFunction` like this:

```c
void myLoadingDraw(OLEDDisplay *display, LoadingStage* stage, uint8_t progress) {
  display->setTextAlignment(TEXT_ALIGN_CENTER);
  display->setFont(ArialMT_Plain_10);
  // stage->process contains the text of the current progress e.q. "Connect to WiFi"
  display->drawString(64, 18, stage->process);
  // you could just print the current process without the progress bar
  display->drawString(64, 28, progress);
}
```

After defining a function like that, you can pass it to the Ui library by use
`ui.setLoadingDrawFunction(myLoadingDraw)`.


### Text Logging

It is always useful to display some text on the display without worrying to much
where it goes and managing it. In 3.0 we made the `OLEDDisplay` class implement
[`Print`](https://github.com/arduino/Arduino/blob/master/hardware/arduino/avr/cores/arduino/Print.h)
so you can use it like you would use `Serial`. We calls this feature `LogBuffer`
and the only thing you have to do is to define how many lines you want to display
and how many characters there are on average on each. This is done by calling
`setLogBuffer(lines, chars);`. If there is not enough memory the function will
return false.

After that you can draw the `LogBuffer` anywhere you want by calling `drawLogBuffer(x, y)`.
(Note: You have to call `display()` to update the screen)
We made a [video](https://www.youtube.com/watch?v=8Fiss77A3TE) showing this feature in action.


================================================
FILE: UPGRADE-4.0.md
================================================
# Upgrade from 3.x to 4.0

There are changes that breaks compatibility with older versions.

1. You'll have to change data type for all your binary resources such as images and fonts from
    
    ```c
    const char MySymbol[] PROGMEM = {
    ```
    
    to
    
    ```c
    const uint8_t MySymbol[] PROGMEM = {
    ```

1. Arguments of `setContrast` from `char` to `uint8_t`
    
    ```c++
    void OLEDDisplay::setContrast(char contrast, char precharge, char comdetect);
    ```
    
    to
    
    ```c++
    void OLEDDisplay::setContrast(uint8_t contrast, uint8_t precharge, uint8_t comdetect);
    ```


================================================
FILE: component.mk
================================================
COMPONENT_ADD_INCLUDEDIRS := src
COMPONENT_SRCDIRS := src
CXXFLAGS += -Wno-ignored-qualifiers


================================================
FILE: examples/SSD1306ClockDemo/SSD1306ClockDemo.ino
================================================
/**
   The MIT License (MIT)

   Copyright (c) 2018 by ThingPulse, Daniel Eichhorn

   Permission is hereby granted, free of charge, to any person obtaining a copy
   of this software and associated documentation files (the "Software"), to deal
   in the Software without restriction, including without limitation the rights
   to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
   copies of the Software, and to permit persons to whom the Software is
   furnished to do so, subject to the following conditions:

   The above copyright notice and this permission notice shall be included in all
   copies or substantial portions of the Software.

   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
   AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
   OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
   SOFTWARE.

   ThingPulse invests considerable time and money to develop these open source libraries.
   Please support us by buying our products (and not the clones) from
   https://thingpulse.com

*/

// Install https://github.com/PaulStoffregen/Time
#include <TimeLib.h>

// Include the correct display library
// For a connection via I2C using Wire include
#include <Wire.h>  // Only needed for Arduino 1.6.5 and earlier
#include "SSD1306Wire.h" // legacy include: `#include "SSD1306.h"`
// or #include "SH1106Wire.h", legacy include: `#include "SH1106.h"`
// For a connection via I2C using brzo_i2c (must be installed) include
// #include <brzo_i2c.h> // Only needed for Arduino 1.6.5 and earlier
// #include "SSD1306Brzo.h"
// #include "SH1106Brzo.h"
// For a connection via SPI include
// #include <SPI.h> // Only needed for Arduino 1.6.5 and earlier
// #include "SSD1306Spi.h"
// #include "SH1106SPi.h"

// Include the UI lib
#include "OLEDDisplayUi.h"

// Include custom images
#include "images.h"

// Use the corresponding display class:

// Initialize the OLED display using SPI
// D5 -> CLK
// D7 -> MOSI (DOUT)
// D0 -> RES
// D2 -> DC
// D8 -> CS
// SSD1306Spi        display(D0, D2, D8);
// or
// SH1106Spi         display(D0, D2);

// Initialize the OLED display using brzo_i2c
// D3 -> SDA
// D5 -> SCL
// SSD1306Brzo display(0x3c, D3, D5);
// or
// SH1106Brzo  display(0x3c, D3, D5);

// Initialize the OLED display using Wire library
SSD1306Wire display(0x3c, SDA, SCL);   // ADDRESS, SDA, SCL  -  SDA and SCL usually populate automatically based on your board's pins_arduino.h e.g. https://github.com/esp8266/Arduino/blob/master/variants/nodemcu/pins_arduino.h
// SH1106Wire display(0x3c, SDA, SCL);

OLEDDisplayUi ui ( &display );

int screenW = 128;
int screenH = 64;
int clockCenterX = screenW / 2;
int clockCenterY = ((screenH - 16) / 2) + 16; // top yellow part is 16 px height
int clockRadius = 23;

// utility function for digital clock display: prints leading 0
String twoDigits(int digits) {
  if (digits < 10) {
    String i = '0' + String(digits);
    return i;
  }
  else {
    return String(digits);
  }
}

void clockOverlay(OLEDDisplay *display, OLEDDisplayUiState* state) {

}

void analogClockFrame(OLEDDisplay *display, OLEDDisplayUiState* state, int16_t x, int16_t y) {
  //  ui.disableIndicator();

  // Draw the clock face
  //  display->drawCircle(clockCenterX + x, clockCenterY + y, clockRadius);
  display->drawCircle(clockCenterX + x, clockCenterY + y, 2);
  //
  //hour ticks
  for ( int z = 0; z < 360; z = z + 30 ) {
    //Begin at 0° and stop at 360°
    float angle = z ;
    angle = ( angle / 57.29577951 ) ; //Convert degrees to radians
    int x2 = ( clockCenterX + ( sin(angle) * clockRadius ) );
    int y2 = ( clockCenterY - ( cos(angle) * clockRadius ) );
    int x3 = ( clockCenterX + ( sin(angle) * ( clockRadius - ( clockRadius / 8 ) ) ) );
    int y3 = ( clockCenterY - ( cos(angle) * ( clockRadius - ( clockRadius / 8 ) ) ) );
    display->drawLine( x2 + x , y2 + y , x3 + x , y3 + y);
  }

  // display second hand
  float angle = second() * 6 ;
  angle = ( angle / 57.29577951 ) ; //Convert degrees to radians
  int x3 = ( clockCenterX + ( sin(angle) * ( clockRadius - ( clockRadius / 5 ) ) ) );
  int y3 = ( clockCenterY - ( cos(angle) * ( clockRadius - ( clockRadius / 5 ) ) ) );
  display->drawLine( clockCenterX + x , clockCenterY + y , x3 + x , y3 + y);
  //
  // display minute hand
  angle = minute() * 6 ;
  angle = ( angle / 57.29577951 ) ; //Convert degrees to radians
  x3 = ( clockCenterX + ( sin(angle) * ( clockRadius - ( clockRadius / 4 ) ) ) );
  y3 = ( clockCenterY - ( cos(angle) * ( clockRadius - ( clockRadius / 4 ) ) ) );
  display->drawLine( clockCenterX + x , clockCenterY + y , x3 + x , y3 + y);
  //
  // display hour hand
  angle = hour() * 30 + int( ( minute() / 12 ) * 6 )   ;
  angle = ( angle / 57.29577951 ) ; //Convert degrees to radians
  x3 = ( clockCenterX + ( sin(angle) * ( clockRadius - ( clockRadius / 2 ) ) ) );
  y3 = ( clockCenterY - ( cos(angle) * ( clockRadius - ( clockRadius / 2 ) ) ) );
  display->drawLine( clockCenterX + x , clockCenterY + y , x3 + x , y3 + y);
}

void digitalClockFrame(OLEDDisplay *display, OLEDDisplayUiState* state, int16_t x, int16_t y) {
  String timenow = String(hour()) + ":" + twoDigits(minute()) + ":" + twoDigits(second());
  display->setTextAlignment(TEXT_ALIGN_CENTER);
  display->setFont(ArialMT_Plain_24);
  display->drawString(clockCenterX + x , clockCenterY + y, timenow );
}

// This array keeps function pointers to all frames
// frames are the single views that slide in
FrameCallback frames[] = { analogClockFrame, digitalClockFrame };

// how many frames are there?
int frameCount = 2;

// Overlays are statically drawn on top of a frame eg. a clock
OverlayCallback overlays[] = { clockOverlay };
int overlaysCount = 1;

void setup() {
  Serial.begin(115200);
  Serial.println();

  // The ESP is capable of rendering 60fps in 80Mhz mode
  // but that won't give you much time for anything else
  // run it in 160Mhz mode or just set it to 30 fps
  ui.setTargetFPS(60);

  // Customize the active and inactive symbol
  ui.setActiveSymbol(activeSymbol);
  ui.setInactiveSymbol(inactiveSymbol);

  // You can change this to
  // TOP, LEFT, BOTTOM, RIGHT
  ui.setIndicatorPosition(TOP);

  // Defines where the first frame is located in the bar.
  ui.setIndicatorDirection(LEFT_RIGHT);

  // You can change the transition that is used
  // SLIDE_LEFT, SLIDE_RIGHT, SLIDE_UP, SLIDE_DOWN
  ui.setFrameAnimation(SLIDE_LEFT);

  // Add frames
  ui.setFrames(frames, frameCount);

  // Add overlays
  ui.setOverlays(overlays, overlaysCount);

  // Initialising the UI will init the display too.
  ui.init();

  display.flipScreenVertically();

  unsigned long secsSinceStart = millis();
  // Unix time starts on Jan 1 1970. In seconds, that's 2208988800:
  const unsigned long seventyYears = 2208988800UL;
  // subtract seventy years:
  unsigned long epoch = secsSinceStart - seventyYears * SECS_PER_HOUR;
  setTime(epoch);

}


void loop() {
  int remainingTimeBudget = ui.update();

  if (remainingTimeBudget > 0) {
    // You can do some work here
    // Don't do stuff if you are below your
    // time budget.
    delay(remainingTimeBudget);
  }
}


================================================
FILE: examples/SSD1306ClockDemo/images.h
================================================
const uint8_t activeSymbol[] PROGMEM = {
    B00000000,
    B00000000,
    B00011000,
    B00100100,
    B01000010,
    B01000010,
    B00100100,
    B00011000
};

const uint8_t inactiveSymbol[] PROGMEM = {
    B00000000,
    B00000000,
    B00000000,
    B00000000,
    B00011000,
    B00011000,
    B00000000,
    B00000000
};


================================================
FILE: examples/SSD1306DrawingDemo/SSD1306DrawingDemo.ino
================================================
/**
   The MIT License (MIT)

   Copyright (c) 2018 by ThingPulse, Daniel Eichhorn
   Copyright (c) 2018 by Fabrice Weinberg

   Permission is hereby granted, free of charge, to any person obtaining a copy
   of this software and associated documentation files (the "Software"), to deal
   in the Software without restriction, including without limitation the rights
   to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
   copies of the Software, and to permit persons to whom the Software is
   furnished to do so, subject to the following conditions:

   The above copyright notice and this permission notice shall be included in all
   copies or substantial portions of the Software.

   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
   AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
   OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
   SOFTWARE.

   ThingPulse invests considerable time and money to develop these open source libraries.
   Please support us by buying our products (and not the clones) from
   https://thingpulse.com

*/

// Include the correct display library
// For a connection via I2C using Wire include
#include <Wire.h>  // Only needed for Arduino 1.6.5 and earlier
#include "SSD1306Wire.h" // legacy include: `#include "SSD1306.h"`
// or #include "SH1106Wire.h", legacy include: `#include "SH1106.h"`
// For a connection via I2C using brzo_i2c (must be installed) include
// #include <brzo_i2c.h> // Only needed for Arduino 1.6.5 and earlier
// #include "SSD1306Brzo.h"
// #include "SH1106Brzo.h"
// For a connection via SPI include
// #include <SPI.h> // Only needed for Arduino 1.6.5 and earlier
// #include "SSD1306Spi.h"
// #include "SH1106SPi.h"

// Use the corresponding display class:

// Initialize the OLED display using SPI
// D5 -> CLK
// D7 -> MOSI (DOUT)
// D0 -> RES
// D2 -> DC
// D8 -> CS
// SSD1306Spi        display(D0, D2, D8);
// or
// SH1106Spi         display(D0, D2);

// Initialize the OLED display using brzo_i2c
// D3 -> SDA
// D5 -> SCL
// SSD1306Brzo display(0x3c, D3, D5);
// or
// SH1106Brzo  display(0x3c, D3, D5);

// Initialize the OLED display using Wire library
SSD1306Wire display(0x3c, SDA, SCL);   // ADDRESS, SDA, SCL  -  SDA and SCL usually populate automatically based on your board's pins_arduino.h e.g. https://github.com/esp8266/Arduino/blob/master/variants/nodemcu/pins_arduino.h
// SH1106Wire display(0x3c, SDA, SCL);

// Adapted from Adafruit_SSD1306
void drawLines() {
  for (int16_t i = 0; i < display.getWidth(); i += 4) {
    display.drawLine(0, 0, i, display.getHeight() - 1);
    display.display();
    delay(10);
  }
  for (int16_t i = 0; i < display.getHeight(); i += 4) {
    display.drawLine(0, 0, display.getWidth() - 1, i);
    display.display();
    delay(10);
  }
  delay(250);

  display.clear();
  for (int16_t i = 0; i < display.getWidth(); i += 4) {
    display.drawLine(0, display.getHeight() - 1, i, 0);
    display.display();
    delay(10);
  }
  for (int16_t i = display.getHeight() - 1; i >= 0; i -= 4) {
    display.drawLine(0, display.getHeight() - 1, display.getWidth() - 1, i);
    display.display();
    delay(10);
  }
  delay(250);

  display.clear();
  for (int16_t i = display.getWidth() - 1; i >= 0; i -= 4) {
    display.drawLine(display.getWidth() - 1, display.getHeight() - 1, i, 0);
    display.display();
    delay(10);
  }
  for (int16_t i = display.getHeight() - 1; i >= 0; i -= 4) {
    display.drawLine(display.getWidth() - 1, display.getHeight() - 1, 0, i);
    display.display();
    delay(10);
  }
  delay(250);
  display.clear();
  for (int16_t i = 0; i < display.getHeight(); i += 4) {
    display.drawLine(display.getWidth() - 1, 0, 0, i);
    display.display();
    delay(10);
  }
  for (int16_t i = 0; i < display.getWidth(); i += 4) {
    display.drawLine(display.getWidth() - 1, 0, i, display.getHeight() - 1);
    display.display();
    delay(10);
  }
  delay(250);
}

// Adapted from Adafruit_SSD1306
void drawRect(void) {
  for (int16_t i = 0; i < display.getHeight() / 2; i += 2) {
    display.drawRect(i, i, display.getWidth() - 2 * i, display.getHeight() - 2 * i);
    display.display();
    delay(10);
  }
}

// Adapted from Adafruit_SSD1306
void fillRect(void) {
  uint8_t color = 1;
  for (int16_t i = 0; i < display.getHeight() / 2; i += 3) {
    display.setColor((color % 2 == 0) ? BLACK : WHITE); // alternate colors
    display.fillRect(i, i, display.getWidth() - i * 2, display.getHeight() - i * 2);
    display.display();
    delay(10);
    color++;
  }
  // Reset back to WHITE
  display.setColor(WHITE);
}

// Adapted from Adafruit_SSD1306
void drawCircle(void) {
  for (int16_t i = 0; i < display.getHeight(); i += 2) {
    display.drawCircle(display.getWidth() / 2, display.getHeight() / 2, i);
    display.display();
    delay(10);
  }
  delay(1000);
  display.clear();

  // This will draw the part of the circel in quadrant 1
  // Quadrants are numberd like this:
  //   0010 | 0001
  //  ------|-----
  //   0100 | 1000
  //
  display.drawCircleQuads(display.getWidth() / 2, display.getHeight() / 2, display.getHeight() / 4, 0b00000001);
  display.display();
  delay(200);
  display.drawCircleQuads(display.getWidth() / 2, display.getHeight() / 2, display.getHeight() / 4, 0b00000011);
  display.display();
  delay(200);
  display.drawCircleQuads(display.getWidth() / 2, display.getHeight() / 2, display.getHeight() / 4, 0b00000111);
  display.display();
  delay(200);
  display.drawCircleQuads(display.getWidth() / 2, display.getHeight() / 2, display.getHeight() / 4, 0b00001111);
  display.display();
}

void printBuffer(void) {
  // Some test data
  const char* test[] = {
    "Hello",
    "World" ,
    "----",
    "Show off",
    "how",
    "the log buffer",
    "is",
    "working.",
    "Even",
    "scrolling is",
    "working"
  };
  display.clear();
  for (uint8_t i = 0; i < 11; i++) {
    // Print to the screen
    display.println(test[i]);
    delay(500);
  }
}

void setup() {
  display.init();

  // display.flipScreenVertically();

  display.setContrast(255);

  drawLines();
  delay(1000);
  display.clear();

  drawRect();
  delay(1000);
  display.clear();

  fillRect();
  delay(1000);
  display.clear();

  drawCircle();
  delay(1000);
  display.clear();

  printBuffer();
  delay(1000);
  display.clear();
}

void loop() { }


================================================
FILE: examples/SSD1306FontTryout/Dialog_plain_6.h
================================================
// Created by http://oleddisplay.squix.ch/ Consider a donation
// In case of problems make sure that you are using the font file with the correct version!
const char Dialog_plain_6[] PROGMEM = {
	0x06, // Width: 6
	0x08, // Height: 8
	0x20, // First Char: 32
	0xE0, // Numbers of Chars: 224

	// Jump Table:
	0xFF, 0xFF, 0x00, 0x02,  // 32:65535
	0x00, 0x00, 0x02, 0x02,  // 33:0
	0x00, 0x02, 0x02, 0x03,  // 34:2
	0x00, 0x04, 0x05, 0x05,  // 35:4
	0x00, 0x09, 0x04, 0x04,  // 36:9
	0x00, 0x0D, 0x06, 0x06,  // 37:13
	0x00, 0x13, 0x05, 0x05,  // 38:19
	0x00, 0x18, 0x02, 0x02,  // 39:24
	0x00, 0x1A, 0x02, 0x02,  // 40:26
	0x00, 0x1C, 0x02, 0x02,  // 41:28
	0x00, 0x1E, 0x03, 0x03,  // 42:30
	0x00, 0x21, 0x05, 0x05,  // 43:33
	0x00, 0x26, 0x02, 0x02,  // 44:38
	0x00, 0x28, 0x02, 0x02,  // 45:40
	0x00, 0x2A, 0x02, 0x02,  // 46:42
	0x00, 0x2C, 0x02, 0x02,  // 47:44
	0x00, 0x2E, 0x04, 0x04,  // 48:46
	0x00, 0x32, 0x04, 0x04,  // 49:50
	0x00, 0x36, 0x04, 0x04,  // 50:54
	0x00, 0x3A, 0x04, 0x04,  // 51:58
	0x00, 0x3E, 0x04, 0x04,  // 52:62
	0x00, 0x42, 0x04, 0x04,  // 53:66
	0x00, 0x46, 0x04, 0x04,  // 54:70
	0x00, 0x4A, 0x04, 0x04,  // 55:74
	0x00, 0x4E, 0x04, 0x04,  // 56:78
	0x00, 0x52, 0x04, 0x04,  // 57:82
	0x00, 0x56, 0x02, 0x02,  // 58:86
	0x00, 0x58, 0x02, 0x02,  // 59:88
	0x00, 0x5A, 0x05, 0x05,  // 60:90
	0x00, 0x5F, 0x05, 0x05,  // 61:95
	0x00, 0x64, 0x05, 0x05,  // 62:100
	0x00, 0x69, 0x03, 0x03,  // 63:105
	0x00, 0x6C, 0x06, 0x06,  // 64:108
	0x00, 0x72, 0x04, 0x04,  // 65:114
	0x00, 0x76, 0x04, 0x04,  // 66:118
	0x00, 0x7A, 0x04, 0x04,  // 67:122
	0x00, 0x7E, 0x05, 0x05,  // 68:126
	0x00, 0x83, 0x04, 0x04,  // 69:131
	0x00, 0x87, 0x03, 0x03,  // 70:135
	0x00, 0x8A, 0x05, 0x05,  // 71:138
	0x00, 0x8F, 0x04, 0x05,  // 72:143
	0x00, 0x93, 0x02, 0x02,  // 73:147
	0x00, 0x95, 0x02, 0x02,  // 74:149
	0x00, 0x97, 0x04, 0x04,  // 75:151
	0x00, 0x9B, 0x03, 0x03,  // 76:155
	0x00, 0x9E, 0x05, 0x05,  // 77:158
	0x00, 0xA3, 0x04, 0x04,  // 78:163
	0x00, 0xA7, 0x05, 0x05,  // 79:167
	0x00, 0xAC, 0x04, 0x04,  // 80:172
	0x00, 0xB0, 0x05, 0x05,  // 81:176
	0x00, 0xB5, 0x04, 0x04,  // 82:181
	0x00, 0xB9, 0x04, 0x04,  // 83:185
	0x00, 0xBD, 0x04, 0x04,  // 84:189
	0x00, 0xC1, 0x04, 0x04,  // 85:193
	0x00, 0xC5, 0x04, 0x04,  // 86:197
	0x00, 0xC9, 0x06, 0x06,  // 87:201
	0x00, 0xCF, 0x04, 0x04,  // 88:207
	0x00, 0xD3, 0x04, 0x04,  // 89:211
	0x00, 0xD7, 0x04, 0x04,  // 90:215
	0x00, 0xDB, 0x02, 0x02,  // 91:219
	0x00, 0xDD, 0x02, 0x02,  // 92:221
	0x00, 0xDF, 0x02, 0x02,  // 93:223
	0x00, 0xE1, 0x05, 0x05,  // 94:225
	0x00, 0xE6, 0x03, 0x03,  // 95:230
	0x00, 0xE9, 0x02, 0x03,  // 96:233
	0x00, 0xEB, 0x04, 0x04,  // 97:235
	0x00, 0xEF, 0x04, 0x04,  // 98:239
	0x00, 0xF3, 0x03, 0x03,  // 99:243
	0x00, 0xF6, 0x04, 0x04,  // 100:246
	0x00, 0xFA, 0x04, 0x04,  // 101:250
	0x00, 0xFE, 0x02, 0x02,  // 102:254
	0x01, 0x00, 0x04, 0x04,  // 103:256
	0x01, 0x04, 0x04, 0x04,  // 104:260
	0x01, 0x08, 0x02, 0x02,  // 105:264
	0x01, 0x0A, 0x02, 0x02,  // 106:266
	0x01, 0x0C, 0x03, 0x03,  // 107:268
	0x01, 0x0F, 0x02, 0x02,  // 108:271
	0x01, 0x11, 0x06, 0x06,  // 109:273
	0x01, 0x17, 0x04, 0x04,  // 110:279
	0x01, 0x1B, 0x04, 0x04,  // 111:283
	0x01, 0x1F, 0x04, 0x04,  // 112:287
	0x01, 0x23, 0x04, 0x04,  // 113:291
	0x01, 0x27, 0x02, 0x02,  // 114:295
	0x01, 0x29, 0x03, 0x03,  // 115:297
	0x01, 0x2C, 0x02, 0x02,  // 116:300
	0x01, 0x2E, 0x04, 0x04,  // 117:302
	0x01, 0x32, 0x03, 0x04,  // 118:306
	0x01, 0x35, 0x04, 0x05,  // 119:309
	0x01, 0x39, 0x03, 0x04,  // 120:313
	0x01, 0x3C, 0x03, 0x04,  // 121:316
	0x01, 0x3F, 0x03, 0x03,  // 122:319
	0x01, 0x42, 0x04, 0x04,  // 123:322
	0x01, 0x46, 0x02, 0x02,  // 124:326
	0x01, 0x48, 0x04, 0x04,  // 125:328
	0x01, 0x4C, 0x05, 0x05,  // 126:332
	0x01, 0x51, 0x03, 0x04,  // 127:337
	0x01, 0x54, 0x03, 0x04,  // 128:340
	0x01, 0x57, 0x03, 0x04,  // 129:343
	0x01, 0x5A, 0x03, 0x04,  // 130:346
	0x01, 0x5D, 0x03, 0x04,  // 131:349
	0x01, 0x60, 0x03, 0x04,  // 132:352
	0x01, 0x63, 0x03, 0x04,  // 133:355
	0x01, 0x66, 0x03, 0x04,  // 134:358
	0x01, 0x69, 0x03, 0x04,  // 135:361
	0x01, 0x6C, 0x03, 0x04,  // 136:364
	0x01, 0x6F, 0x03, 0x04,  // 137:367
	0x01, 0x72, 0x03, 0x04,  // 138:370
	0x01, 0x75, 0x03, 0x04,  // 139:373
	0x01, 0x78, 0x03, 0x04,  // 140:376
	0x01, 0x7B, 0x03, 0x04,  // 141:379
	0x01, 0x7E, 0x03, 0x04,  // 142:382
	0x01, 0x81, 0x03, 0x04,  // 143:385
	0x01, 0x84, 0x03, 0x04,  // 144:388
	0x01, 0x87, 0x03, 0x04,  // 145:391
	0x01, 0x8A, 0x03, 0x04,  // 146:394
	0x01, 0x8D, 0x03, 0x04,  // 147:397
	0x01, 0x90, 0x03, 0x04,  // 148:400
	0x01, 0x93, 0x03, 0x04,  // 149:403
	0x01, 0x96, 0x03, 0x04,  // 150:406
	0x01, 0x99, 0x03, 0x04,  // 151:409
	0x01, 0x9C, 0x03, 0x04,  // 152:412
	0x01, 0x9F, 0x03, 0x04,  // 153:415
	0x01, 0xA2, 0x03, 0x04,  // 154:418
	0x01, 0xA5, 0x03, 0x04,  // 155:421
	0x01, 0xA8, 0x03, 0x04,  // 156:424
	0x01, 0xAB, 0x03, 0x04,  // 157:427
	0x01, 0xAE, 0x03, 0x04,  // 158:430
	0x01, 0xB1, 0x03, 0x04,  // 159:433
	0xFF, 0xFF, 0x00, 0x02,  // 160:65535
	0x01, 0xB4, 0x02, 0x02,  // 161:436
	0x01, 0xB6, 0x04, 0x04,  // 162:438
	0x01, 0xBA, 0x04, 0x04,  // 163:442
	0x01, 0xBE, 0x04, 0x04,  // 164:446
	0x01, 0xC2, 0x04, 0x04,  // 165:450
	0x01, 0xC6, 0x02, 0x02,  // 166:454
	0x01, 0xC8, 0x03, 0x03,  // 167:456
	0x01, 0xCB, 0x02, 0x03,  // 168:459
	0x01, 0xCD, 0x05, 0x06,  // 169:461
	0x01, 0xD2, 0x03, 0x03,  // 170:466
	0x01, 0xD5, 0x03, 0x04,  // 171:469
	0x01, 0xD8, 0x05, 0x05,  // 172:472
	0x01, 0xDD, 0x02, 0x02,  // 173:477
	0x01, 0xDF, 0x05, 0x06,  // 174:479
	0x01, 0xE4, 0x03, 0x03,  // 175:484
	0x01, 0xE7, 0x03, 0x03,  // 176:487
	0x01, 0xEA, 0x05, 0x05,  // 177:490
	0x01, 0xEF, 0x02, 0x02,  // 178:495
	0x01, 0xF1, 0x02, 0x02,  // 179:497
	0x01, 0xF3, 0x02, 0x03,  // 180:499
	0x01, 0xF5, 0x04, 0x04,  // 181:501
	0x01, 0xF9, 0x03, 0x04,  // 182:505
	0x01, 0xFC, 0x02, 0x02,  // 183:508
	0x01, 0xFE, 0x02, 0x03,  // 184:510
	0x02, 0x00, 0x02, 0x02,  // 185:512
	0x02, 0x02, 0x03, 0x03,  // 186:514
	0x02, 0x05, 0x03, 0x04,  // 187:517
	0x02, 0x08, 0x06, 0x06,  // 188:520
	0x02, 0x0E, 0x06, 0x06,  // 189:526
	0x02, 0x14, 0x06, 0x06,  // 190:532
	0x02, 0x1A, 0x03, 0x03,  // 191:538
	0x02, 0x1D, 0x04, 0x04,  // 192:541
	0x02, 0x21, 0x04, 0x04,  // 193:545
	0x02, 0x25, 0x04, 0x04,  // 194:549
	0x02, 0x29, 0x04, 0x04,  // 195:553
	0x02, 0x2D, 0x04, 0x04,  // 196:557
	0x02, 0x31, 0x04, 0x04,  // 197:561
	0x02, 0x35, 0x06, 0x06,  // 198:565
	0x02, 0x3B, 0x04, 0x04,  // 199:571
	0x02, 0x3F, 0x04, 0x04,  // 200:575
	0x02, 0x43, 0x04, 0x04,  // 201:579
	0x02, 0x47, 0x04, 0x04,  // 202:583
	0x02, 0x4B, 0x04, 0x04,  // 203:587
	0x02, 0x4F, 0x02, 0x02,  // 204:591
	0x02, 0x51, 0x02, 0x02,  // 205:593
	0x02, 0x53, 0x02, 0x02,  // 206:595
	0x02, 0x55, 0x02, 0x02,  // 207:597
	0x02, 0x57, 0x05, 0x05,  // 208:599
	0x02, 0x5C, 0x04, 0x04,  // 209:604
	0x02, 0x60, 0x05, 0x05,  // 210:608
	0x02, 0x65, 0x05, 0x05,  // 211:613
	0x02, 0x6A, 0x05, 0x05,  // 212:618
	0x02, 0x6F, 0x05, 0x05,  // 213:623
	0x02, 0x74, 0x05, 0x05,  // 214:628
	0x02, 0x79, 0x04, 0x05,  // 215:633
	0x02, 0x7D, 0x05, 0x05,  // 216:637
	0x02, 0x82, 0x04, 0x04,  // 217:642
	0x02, 0x86, 0x04, 0x04,  // 218:646
	0x02, 0x8A, 0x04, 0x04,  // 219:650
	0x02, 0x8E, 0x04, 0x04,  // 220:654
	0x02, 0x92, 0x04, 0x04,  // 221:658
	0x02, 0x96, 0x04, 0x04,  // 222:662
	0x02, 0x9A, 0x04, 0x04,  // 223:666
	0x02, 0x9E, 0x04, 0x04,  // 224:670
	0x02, 0xA2, 0x04, 0x04,  // 225:674
	0x02, 0xA6, 0x04, 0x04,  // 226:678
	0x02, 0xAA, 0x04, 0x04,  // 227:682
	0x02, 0xAE, 0x04, 0x04,  // 228:686
	0x02, 0xB2, 0x04, 0x04,  // 229:690
	0x02, 0xB6, 0x06, 0x06,  // 230:694
	0x02, 0xBC, 0x03, 0x03,  // 231:700
	0x02, 0xBF, 0x04, 0x04,  // 232:703
	0x02, 0xC3, 0x04, 0x04,  // 233:707
	0x02, 0xC7, 0x04, 0x04,  // 234:711
	0x02, 0xCB, 0x04, 0x04,  // 235:715
	0x02, 0xCF, 0x02, 0x02,  // 236:719
	0x02, 0xD1, 0x02, 0x02,  // 237:721
	0x02, 0xD3, 0x02, 0x02,  // 238:723
	0x02, 0xD5, 0x02, 0x02,  // 239:725
	0x02, 0xD7, 0x04, 0x04,  // 240:727
	0x02, 0xDB, 0x04, 0x04,  // 241:731
	0x02, 0xDF, 0x04, 0x04,  // 242:735
	0x02, 0xE3, 0x04, 0x04,  // 243:739
	0x02, 0xE7, 0x04, 0x04,  // 244:743
	0x02, 0xEB, 0x04, 0x04,  // 245:747
	0x02, 0xEF, 0x04, 0x04,  // 246:751
	0x02, 0xF3, 0x05, 0x05,  // 247:755
	0x02, 0xF8, 0x04, 0x04,  // 248:760
	0x02, 0xFC, 0x04, 0x04,  // 249:764
	0x03, 0x00, 0x04, 0x04,  // 250:768
	0x03, 0x04, 0x04, 0x04,  // 251:772
	0x03, 0x08, 0x04, 0x04,  // 252:776
	0x03, 0x0C, 0x03, 0x04,  // 253:780
	0x03, 0x0F, 0x04, 0x04,  // 254:783
	0x03, 0x13, 0x03, 0x04,  // 255:787

	// Font Data:
	0x00,0x2C,	// 33
	0x00,0x0C,	// 34
	0x00,0x18,0x1C,0x38,0x18,	// 35
	0x00,0x2C,0x7E,0x3C,	// 36
	0x00,0x0C,0x2C,0x18,0x34,0x30,	// 37
	0x00,0x30,0x3C,0x34,0x30,	// 38
	0x00,0x0C,	// 39
	0x00,0x1C,	// 40
	0x00,0x1C,	// 41
	0x0C,0x0C,0x0C,	// 42
	0x00,0x08,0x08,0x3E,0x08,	// 43
	0x00,0x20,	// 44
	0x00,0x10,	// 45
	0x00,0x20,	// 46
	0x70,0x1C,	// 47
	0x00,0x3C,0x24,0x3C,	// 48
	0x00,0x24,0x3C,0x20,	// 49
	0x00,0x24,0x34,0x3C,	// 50
	0x00,0x24,0x2C,0x34,	// 51
	0x00,0x10,0x18,0x3C,	// 52
	0x00,0x2C,0x2C,0x3C,	// 53
	0x00,0x38,0x34,0x34,	// 54
	0x00,0x04,0x34,0x0C,	// 55
	0x00,0x34,0x2C,0x34,	// 56
	0x00,0x2C,0x2C,0x1C,	// 57
	0x00,0x28,	// 58
	0x00,0x28,	// 59
	0x00,0x08,0x08,0x1C,0x14,	// 60
	0x00,0x14,0x14,0x14,0x14,	// 61
	0x00,0x14,0x1C,0x08,0x08,	// 62
	0x00,0x04,0x24,	// 63
	0x00,0x38,0x54,0x74,0x14,0x08,	// 64
	0x20,0x1C,0x1C,0x20,	// 65
	0x00,0x3C,0x2C,0x34,	// 66
	0x00,0x18,0x24,0x24,	// 67
	0x00,0x3C,0x24,0x24,0x18,	// 68
	0x00,0x3C,0x2C,0x2C,	// 69
	0x00,0x3C,0x0C,	// 70
	0x00,0x18,0x24,0x2C,0x3C,	// 71
	0x00,0x3C,0x08,0x3C,	// 72
	0x00,0x3C,	// 73
	0x40,0x7C,	// 74
	0x00,0x3C,0x3C,0x24,	// 75
	0x00,0x3C,0x20,	// 76
	0x00,0x3C,0x1C,0x0C,0x3C,	// 77
	0x00,0x3C,0x1C,0x3C,	// 78
	0x00,0x18,0x24,0x24,0x18,	// 79
	0x00,0x3C,0x14,0x1C,	// 80
	0x00,0x18,0x24,0x64,0x18,	// 81
	0x00,0x3C,0x34,0x2C,	// 82
	0x00,0x2C,0x2C,0x3C,	// 83
	0x04,0x04,0x3C,0x04,	// 84
	0x00,0x3C,0x20,0x3C,	// 85
	0x04,0x38,0x38,0x04,	// 86
	0x0C,0x30,0x0C,0x0C,0x30,0x0C,	// 87
	0x24,0x3C,0x3C,0x24,	// 88
	0x04,0x0C,0x38,0x0C,	// 89
	0x00,0x24,0x3C,0x2C,	// 90
	0x00,0x3E,	// 91
	0x1C,0x70,	// 92
	0x00,0x22,	// 93
	0x00,0x08,0x04,0x04,0x08,	// 94
	0x40,0x40,0x40,	// 95
	0x00,0x02,	// 96
	0x00,0x30,0x38,0x38,	// 97
	0x00,0x3E,0x28,0x38,	// 98
	0x00,0x38,0x28,	// 99
	0x00,0x38,0x28,0x3E,	// 100
	0x00,0x38,0x38,0x38,	// 101
	0x08,0x3E,	// 102
	0x00,0x78,0x68,0x78,	// 103
	0x00,0x3E,0x08,0x38,	// 104
	0x00,0x3A,	// 105
	0x40,0x7A,	// 106
	0x00,0x3E,0x38,	// 107
	0x00,0x3E,	// 108
	0x00,0x38,0x08,0x38,0x08,0x38,	// 109
	0x00,0x38,0x08,0x38,	// 110
	0x00,0x38,0x28,0x38,	// 111
	0x00,0x78,0x28,0x38,	// 112
	0x00,0x38,0x28,0x78,	// 113
	0x00,0x38,	// 114
	0x00,0x28,0x38,	// 115
	0x00,0x3C,	// 116
	0x00,0x38,0x20,0x38,	// 117
	0x08,0x30,0x08,	// 118
	0x38,0x18,0x38,0x18,	// 119
	0x28,0x38,0x28,	// 120
	0x68,0x30,0x08,	// 121
	0x00,0x28,0x38,	// 122
	0x00,0x08,0x76,0x42,	// 123
	0x00,0x7E,	// 124
	0x00,0x42,0x76,0x08,	// 125
	0x00,0x08,0x08,0x08,0x08,	// 126
	0x7C,0x44,0x7C,	// 127
	0x7C,0x44,0x7C,	// 128
	0x7C,0x44,0x7C,	// 129
	0x7C,0x44,0x7C,	// 130
	0x7C,0x44,0x7C,	// 131
	0x7C,0x44,0x7C,	// 132
	0x7C,0x44,0x7C,	// 133
	0x7C,0x44,0x7C,	// 134
	0x7C,0x44,0x7C,	// 135
	0x7C,0x44,0x7C,	// 136
	0x7C,0x44,0x7C,	// 137
	0x7C,0x44,0x7C,	// 138
	0x7C,0x44,0x7C,	// 139
	0x7C,0x44,0x7C,	// 140
	0x7C,0x44,0x7C,	// 141
	0x7C,0x44,0x7C,	// 142
	0x7C,0x44,0x7C,	// 143
	0x7C,0x44,0x7C,	// 144
	0x7C,0x44,0x7C,	// 145
	0x7C,0x44,0x7C,	// 146
	0x7C,0x44,0x7C,	// 147
	0x7C,0x44,0x7C,	// 148
	0x7C,0x44,0x7C,	// 149
	0x7C,0x44,0x7C,	// 150
	0x7C,0x44,0x7C,	// 151
	0x7C,0x44,0x7C,	// 152
	0x7C,0x44,0x7C,	// 153
	0x7C,0x44,0x7C,	// 154
	0x7C,0x44,0x7C,	// 155
	0x7C,0x44,0x7C,	// 156
	0x7C,0x44,0x7C,	// 157
	0x7C,0x44,0x7C,	// 158
	0x7C,0x44,0x7C,	// 159
	0x00,0x68,	// 161
	0x00,0x38,0x7C,0x28,	// 162
	0x28,0x3C,0x2C,0x24,	// 163
	0x00,0x38,0x28,0x38,	// 164
	0x00,0x2C,0x38,0x2C,	// 165
	0x00,0x6C,	// 166
	0x00,0x5C,0x74,	// 167
	0x00,0x02,	// 168
	0x00,0x18,0x24,0x3C,0x18,	// 169
	0x00,0x2C,0x2C,	// 170
	0x00,0x10,0x10,	// 171
	0x00,0x08,0x08,0x08,0x18,	// 172
	0x00,0x10,	// 173
	0x00,0x18,0x34,0x34,0x18,	// 174
	0x00,0x04,0x04,	// 175
	0x00,0x0C,0x0C,	// 176
	0x28,0x28,0x3C,0x28,0x28,	// 177
	0x00,0x0C,	// 178
	0x00,0x0C,	// 179
	0x00,0x02,	// 180
	0x00,0x78,0x20,0x38,	// 181
	0x7C,0x04,0x7C,	// 182
	0x00,0x10,	// 183
	0x00,0x40,	// 184
	0x00,0x0C,	// 185
	0x00,0x2C,0x2C,	// 186
	0x00,0x10,0x10,	// 187
	0x00,0x2C,0x1C,0x0C,0x20,0x30,	// 188
	0x00,0x2C,0x1C,0x0C,0x30,0x30,	// 189
	0x00,0x2C,0x18,0x04,0x20,0x30,	// 190
	0x00,0x48,0x40,	// 191
	0x20,0x1C,0x1D,0x21,	// 192
	0x20,0x1C,0x1D,0x20,	// 193
	0x20,0x1D,0x1D,0x20,	// 194
	0x20,0x1D,0x1D,0x20,	// 195
	0x20,0x1D,0x1D,0x20,	// 196
	0x20,0x1E,0x1A,0x20,	// 197
	0x20,0x18,0x14,0x3C,0x2C,0x2C,	// 198
	0x00,0x18,0x64,0x24,	// 199
	0x00,0x3D,0x2D,0x2C,	// 200
	0x00,0x3D,0x2C,0x2C,	// 201
	0x00,0x3D,0x2D,0x2C,	// 202
	0x00,0x3D,0x2C,0x2D,	// 203
	0x01,0x3D,	// 204
	0x01,0x3C,	// 205
	0x01,0x3D,	// 206
	0x01,0x3C,	// 207
	0x10,0x3C,0x34,0x24,0x18,	// 208
	0x00,0x3C,0x1D,0x3C,	// 209
	0x00,0x18,0x25,0x25,0x18,	// 210
	0x00,0x18,0x25,0x24,0x18,	// 211
	0x00,0x18,0x25,0x25,0x18,	// 212
	0x00,0x18,0x25,0x25,0x18,	// 213
	0x00,0x19,0x24,0x24,0x19,	// 214
	0x00,0x14,0x1C,0x14,	// 215
	0x00,0x3C,0x34,0x2C,0x3C,	// 216
	0x00,0x3C,0x21,0x3D,	// 217
	0x00,0x3C,0x21,0x3C,	// 218
	0x00,0x3C,0x20,0x3C,	// 219
	0x00,0x3D,0x20,0x3D,	// 220
	0x04,0x0D,0x38,0x0C,	// 221
	0x00,0x3C,0x28,0x38,	// 222
	0x00,0x3E,0x0A,0x36,	// 223
	0x00,0x32,0x38,0x38,	// 224
	0x00,0x32,0x38,0x38,	// 225
	0x00,0x30,0x38,0x38,	// 226
	0x00,0x30,0x3A,0x38,	// 227
	0x00,0x32,0x38,0x3A,	// 228
	0x00,0x30,0x3B,0x3B,	// 229
	0x00,0x30,0x38,0x10,0x38,0x38,	// 230
	0x00,0x78,0x28,	// 231
	0x00,0x3A,0x38,0x38,	// 232
	0x00,0x3A,0x38,0x38,	// 233
	0x00,0x3A,0x3A,0x38,	// 234
	0x00,0x3A,0x38,0x3A,	// 235
	0x02,0x38,	// 236
	0x02,0x38,	// 237
	0x02,0x3A,	// 238
	0x02,0x38,	// 239
	0x00,0x38,0x2E,0x3C,	// 240
	0x02,0x3A,0x08,0x38,	// 241
	0x00,0x3A,0x28,0x38,	// 242
	0x00,0x3A,0x28,0x38,	// 243
	0x00,0x38,0x28,0x38,	// 244
	0x00,0x38,0x2A,0x38,	// 245
	0x00,0x3A,0x28,0x3A,	// 246
	0x00,0x08,0x08,0x1C,0x08,	// 247
	0x00,0x38,0x38,0x38,	// 248
	0x00,0x3A,0x20,0x38,	// 249
	0x00,0x3A,0x20,0x38,	// 250
	0x00,0x38,0x20,0x38,	// 251
	0x00,0x3A,0x20,0x3A,	// 252
	0x68,0x32,0x08,	// 253
	0x00,0x7E,0x28,0x38,	// 254
	0x68,0x32,0x0A	// 255
};

================================================
FILE: examples/SSD1306FontTryout/Dialog_plain_7.h
================================================
// Created by http://oleddisplay.squix.ch/ Consider a donation
// In case of problems make sure that you are using the font file with the correct version!
const char Dialog_plain_7[] PROGMEM = {
	0x07, // Width: 7
	0x09, // Height: 9
	0x20, // First Char: 32
	0xE0, // Numbers of Chars: 224

	// Jump Table:
	0xFF, 0xFF, 0x00, 0x02,  // 32:65535
	0x00, 0x00, 0x03, 0x03,  // 33:0
	0x00, 0x03, 0x03, 0x03,  // 34:3
	0x00, 0x06, 0x0B, 0x06,  // 35:6
	0x00, 0x11, 0x07, 0x04,  // 36:17
	0x00, 0x18, 0x0D, 0x07,  // 37:24
	0x00, 0x25, 0x09, 0x05,  // 38:37
	0x00, 0x2E, 0x03, 0x02,  // 39:46
	0x00, 0x31, 0x05, 0x03,  // 40:49
	0x00, 0x36, 0x05, 0x03,  // 41:54
	0x00, 0x3B, 0x07, 0x04,  // 42:59
	0x00, 0x42, 0x0B, 0x06,  // 43:66
	0x00, 0x4D, 0x03, 0x02,  // 44:77
	0x00, 0x50, 0x05, 0x03,  // 45:80
	0x00, 0x55, 0x03, 0x02,  // 46:85
	0x00, 0x58, 0x03, 0x02,  // 47:88
	0x00, 0x5B, 0x07, 0x04,  // 48:91
	0x00, 0x62, 0x07, 0x04,  // 49:98
	0x00, 0x69, 0x07, 0x04,  // 50:105
	0x00, 0x70, 0x07, 0x04,  // 51:112
	0x00, 0x77, 0x07, 0x04,  // 52:119
	0x00, 0x7E, 0x07, 0x04,  // 53:126
	0x00, 0x85, 0x07, 0x04,  // 54:133
	0x00, 0x8C, 0x07, 0x04,  // 55:140
	0x00, 0x93, 0x07, 0x04,  // 56:147
	0x00, 0x9A, 0x07, 0x04,  // 57:154
	0x00, 0xA1, 0x03, 0x02,  // 58:161
	0x00, 0xA4, 0x03, 0x02,  // 59:164
	0x00, 0xA7, 0x09, 0x06,  // 60:167
	0x00, 0xB0, 0x09, 0x06,  // 61:176
	0x00, 0xB9, 0x09, 0x06,  // 62:185
	0x00, 0xC2, 0x07, 0x04,  // 63:194
	0x00, 0xC9, 0x0D, 0x07,  // 64:201
	0x00, 0xD6, 0x09, 0x05,  // 65:214
	0x00, 0xDF, 0x09, 0x05,  // 66:223
	0x00, 0xE8, 0x09, 0x05,  // 67:232
	0x00, 0xF1, 0x09, 0x05,  // 68:241
	0x00, 0xFA, 0x07, 0x04,  // 69:250
	0x01, 0x01, 0x07, 0x04,  // 70:257
	0x01, 0x08, 0x09, 0x05,  // 71:264
	0x01, 0x11, 0x09, 0x05,  // 72:273
	0x01, 0x1A, 0x03, 0x02,  // 73:282
	0x01, 0x1D, 0x03, 0x02,  // 74:285
	0x01, 0x20, 0x09, 0x05,  // 75:288
	0x01, 0x29, 0x07, 0x04,  // 76:297
	0x01, 0x30, 0x0B, 0x06,  // 77:304
	0x01, 0x3B, 0x09, 0x05,  // 78:315
	0x01, 0x44, 0x09, 0x06,  // 79:324
	0x01, 0x4D, 0x07, 0x04,  // 80:333
	0x01, 0x54, 0x09, 0x06,  // 81:340
	0x01, 0x5D, 0x09, 0x05,  // 82:349
	0x01, 0x66, 0x07, 0x04,  // 83:358
	0x01, 0x6D, 0x07, 0x04,  // 84:365
	0x01, 0x74, 0x09, 0x05,  // 85:372
	0x01, 0x7D, 0x09, 0x05,  // 86:381
	0x01, 0x86, 0x0B, 0x07,  // 87:390
	0x01, 0x91, 0x07, 0x04,  // 88:401
	0x01, 0x98, 0x07, 0x04,  // 89:408
	0x01, 0x9F, 0x09, 0x05,  // 90:415
	0x01, 0xA8, 0x05, 0x03,  // 91:424
	0x01, 0xAD, 0x03, 0x02,  // 92:429
	0x01, 0xB0, 0x05, 0x03,  // 93:432
	0x01, 0xB5, 0x09, 0x06,  // 94:437
	0x01, 0xBE, 0x08, 0x04,  // 95:446
	0x01, 0xC6, 0x01, 0x04,  // 96:454
	0x01, 0xC7, 0x07, 0x04,  // 97:455
	0x01, 0xCE, 0x07, 0x04,  // 98:462
	0x01, 0xD5, 0x07, 0x04,  // 99:469
	0x01, 0xDC, 0x07, 0x04,  // 100:476
	0x01, 0xE3, 0x07, 0x04,  // 101:483
	0x01, 0xEA, 0x03, 0x02,  // 102:490
	0x01, 0xED, 0x07, 0x04,  // 103:493
	0x01, 0xF4, 0x07, 0x04,  // 104:500
	0x01, 0xFB, 0x03, 0x02,  // 105:507
	0x01, 0xFE, 0x03, 0x02,  // 106:510
	0x02, 0x01, 0x07, 0x04,  // 107:513
	0x02, 0x08, 0x03, 0x02,  // 108:520
	0x02, 0x0B, 0x0B, 0x07,  // 109:523
	0x02, 0x16, 0x07, 0x04,  // 110:534
	0x02, 0x1D, 0x07, 0x04,  // 111:541
	0x02, 0x24, 0x07, 0x04,  // 112:548
	0x02, 0x2B, 0x07, 0x04,  // 113:555
	0x02, 0x32, 0x05, 0x03,  // 114:562
	0x02, 0x37, 0x07, 0x04,  // 115:567
	0x02, 0x3E, 0x05, 0x03,  // 116:574
	0x02, 0x43, 0x07, 0x04,  // 117:579
	0x02, 0x4A, 0x07, 0x04,  // 118:586
	0x02, 0x51, 0x09, 0x06,  // 119:593
	0x02, 0x5A, 0x07, 0x04,  // 120:602
	0x02, 0x61, 0x07, 0x04,  // 121:609
	0x02, 0x68, 0x07, 0x04,  // 122:616
	0x02, 0x6F, 0x07, 0x04,  // 123:623
	0x02, 0x76, 0x04, 0x02,  // 124:630
	0x02, 0x7A, 0x07, 0x04,  // 125:634
	0x02, 0x81, 0x09, 0x06,  // 126:641
	0x02, 0x8A, 0x07, 0x04,  // 127:650
	0x02, 0x91, 0x07, 0x04,  // 128:657
	0x02, 0x98, 0x07, 0x04,  // 129:664
	0x02, 0x9F, 0x07, 0x04,  // 130:671
	0x02, 0xA6, 0x07, 0x04,  // 131:678
	0x02, 0xAD, 0x07, 0x04,  // 132:685
	0x02, 0xB4, 0x07, 0x04,  // 133:692
	0x02, 0xBB, 0x07, 0x04,  // 134:699
	0x02, 0xC2, 0x07, 0x04,  // 135:706
	0x02, 0xC9, 0x07, 0x04,  // 136:713
	0x02, 0xD0, 0x07, 0x04,  // 137:720
	0x02, 0xD7, 0x07, 0x04,  // 138:727
	0x02, 0xDE, 0x07, 0x04,  // 139:734
	0x02, 0xE5, 0x07, 0x04,  // 140:741
	0x02, 0xEC, 0x07, 0x04,  // 141:748
	0x02, 0xF3, 0x07, 0x04,  // 142:755
	0x02, 0xFA, 0x07, 0x04,  // 143:762
	0x03, 0x01, 0x07, 0x04,  // 144:769
	0x03, 0x08, 0x07, 0x04,  // 145:776
	0x03, 0x0F, 0x07, 0x04,  // 146:783
	0x03, 0x16, 0x07, 0x04,  // 147:790
	0x03, 0x1D, 0x07, 0x04,  // 148:797
	0x03, 0x24, 0x07, 0x04,  // 149:804
	0x03, 0x2B, 0x07, 0x04,  // 150:811
	0x03, 0x32, 0x07, 0x04,  // 151:818
	0x03, 0x39, 0x07, 0x04,  // 152:825
	0x03, 0x40, 0x07, 0x04,  // 153:832
	0x03, 0x47, 0x07, 0x04,  // 154:839
	0x03, 0x4E, 0x07, 0x04,  // 155:846
	0x03, 0x55, 0x07, 0x04,  // 156:853
	0x03, 0x5C, 0x07, 0x04,  // 157:860
	0x03, 0x63, 0x07, 0x04,  // 158:867
	0x03, 0x6A, 0x07, 0x04,  // 159:874
	0xFF, 0xFF, 0x00, 0x02,  // 160:65535
	0x03, 0x71, 0x03, 0x03,  // 161:881
	0x03, 0x74, 0x07, 0x04,  // 162:884
	0x03, 0x7B, 0x07, 0x04,  // 163:891
	0x03, 0x82, 0x07, 0x04,  // 164:898
	0x03, 0x89, 0x07, 0x04,  // 165:905
	0x03, 0x90, 0x04, 0x02,  // 166:912
	0x03, 0x94, 0x07, 0x04,  // 167:916
	0x03, 0x9B, 0x07, 0x04,  // 168:923
	0x03, 0xA2, 0x0B, 0x07,  // 169:930
	0x03, 0xAD, 0x05, 0x03,  // 170:941
	0x03, 0xB2, 0x07, 0x04,  // 171:946
	0x03, 0xB9, 0x09, 0x06,  // 172:953
	0x03, 0xC2, 0x05, 0x03,  // 173:962
	0x03, 0xC7, 0x0B, 0x07,  // 174:967
	0x03, 0xD2, 0x05, 0x04,  // 175:978
	0x03, 0xD7, 0x05, 0x04,  // 176:983
	0x03, 0xDC, 0x0B, 0x06,  // 177:988
	0x03, 0xE7, 0x05, 0x03,  // 178:999
	0x03, 0xEC, 0x05, 0x03,  // 179:1004
	0x03, 0xF1, 0x03, 0x04,  // 180:1009
	0x03, 0xF4, 0x07, 0x04,  // 181:1012
	0x03, 0xFB, 0x07, 0x04,  // 182:1019
	0x04, 0x02, 0x03, 0x02,  // 183:1026
	0x04, 0x05, 0x03, 0x04,  // 184:1029
	0x04, 0x08, 0x05, 0x03,  // 185:1032
	0x04, 0x0D, 0x05, 0x03,  // 186:1037
	0x04, 0x12, 0x07, 0x04,  // 187:1042
	0x04, 0x19, 0x0D, 0x07,  // 188:1049
	0x04, 0x26, 0x0D, 0x07,  // 189:1062
	0x04, 0x33, 0x0D, 0x07,  // 190:1075
	0x04, 0x40, 0x07, 0x04,  // 191:1088
	0x04, 0x47, 0x09, 0x05,  // 192:1095
	0x04, 0x50, 0x09, 0x05,  // 193:1104
	0x04, 0x59, 0x09, 0x05,  // 194:1113
	0x04, 0x62, 0x09, 0x05,  // 195:1122
	0x04, 0x6B, 0x09, 0x05,  // 196:1131
	0x04, 0x74, 0x09, 0x05,  // 197:1140
	0x04, 0x7D, 0x0B, 0x07,  // 198:1149
	0x04, 0x88, 0x09, 0x05,  // 199:1160
	0x04, 0x91, 0x07, 0x04,  // 200:1169
	0x04, 0x98, 0x07, 0x04,  // 201:1176
	0x04, 0x9F, 0x07, 0x04,  // 202:1183
	0x04, 0xA6, 0x07, 0x04,  // 203:1190
	0x04, 0xAD, 0x03, 0x02,  // 204:1197
	0x04, 0xB0, 0x03, 0x02,  // 205:1200
	0x04, 0xB3, 0x03, 0x02,  // 206:1203
	0x04, 0xB6, 0x03, 0x02,  // 207:1206
	0x04, 0xB9, 0x09, 0x05,  // 208:1209
	0x04, 0xC2, 0x09, 0x05,  // 209:1218
	0x04, 0xCB, 0x09, 0x06,  // 210:1227
	0x04, 0xD4, 0x09, 0x06,  // 211:1236
	0x04, 0xDD, 0x09, 0x06,  // 212:1245
	0x04, 0xE6, 0x09, 0x06,  // 213:1254
	0x04, 0xEF, 0x09, 0x06,  // 214:1263
	0x04, 0xF8, 0x09, 0x06,  // 215:1272
	0x05, 0x01, 0x09, 0x06,  // 216:1281
	0x05, 0x0A, 0x09, 0x05,  // 217:1290
	0x05, 0x13, 0x09, 0x05,  // 218:1299
	0x05, 0x1C, 0x09, 0x05,  // 219:1308
	0x05, 0x25, 0x09, 0x05,  // 220:1317
	0x05, 0x2E, 0x07, 0x04,  // 221:1326
	0x05, 0x35, 0x07, 0x04,  // 222:1333
	0x05, 0x3C, 0x07, 0x04,  // 223:1340
	0x05, 0x43, 0x07, 0x04,  // 224:1347
	0x05, 0x4A, 0x07, 0x04,  // 225:1354
	0x05, 0x51, 0x07, 0x04,  // 226:1361
	0x05, 0x58, 0x07, 0x04,  // 227:1368
	0x05, 0x5F, 0x07, 0x04,  // 228:1375
	0x05, 0x66, 0x07, 0x04,  // 229:1382
	0x05, 0x6D, 0x0B, 0x07,  // 230:1389
	0x05, 0x78, 0x07, 0x04,  // 231:1400
	0x05, 0x7F, 0x07, 0x04,  // 232:1407
	0x05, 0x86, 0x07, 0x04,  // 233:1414
	0x05, 0x8D, 0x07, 0x04,  // 234:1421
	0x05, 0x94, 0x07, 0x04,  // 235:1428
	0x05, 0x9B, 0x03, 0x02,  // 236:1435
	0x05, 0x9E, 0x03, 0x02,  // 237:1438
	0x05, 0xA1, 0x03, 0x02,  // 238:1441
	0x05, 0xA4, 0x03, 0x02,  // 239:1444
	0x05, 0xA7, 0x07, 0x04,  // 240:1447
	0x05, 0xAE, 0x07, 0x04,  // 241:1454
	0x05, 0xB5, 0x07, 0x04,  // 242:1461
	0x05, 0xBC, 0x07, 0x04,  // 243:1468
	0x05, 0xC3, 0x07, 0x04,  // 244:1475
	0x05, 0xCA, 0x07, 0x04,  // 245:1482
	0x05, 0xD1, 0x07, 0x04,  // 246:1489
	0x05, 0xD8, 0x0B, 0x06,  // 247:1496
	0x05, 0xE3, 0x07, 0x04,  // 248:1507
	0x05, 0xEA, 0x07, 0x04,  // 249:1514
	0x05, 0xF1, 0x07, 0x04,  // 250:1521
	0x05, 0xF8, 0x07, 0x04,  // 251:1528
	0x05, 0xFF, 0x07, 0x04,  // 252:1535
	0x06, 0x06, 0x07, 0x04,  // 253:1542
	0x06, 0x0D, 0x07, 0x04,  // 254:1549
	0x06, 0x14, 0x07, 0x04,  // 255:1556

	// Font Data:
	0x00,0x00,0x5C,	// 33
	0x00,0x00,0x0C,	// 34
	0x00,0x00,0x28,0x00,0x7C,0x00,0x68,0x00,0x3C,0x00,0x28,	// 35
	0x00,0x00,0x5C,0x00,0xFE,0x00,0x74,	// 36
	0x00,0x00,0x1C,0x00,0x5C,0x00,0x30,0x00,0x18,0x00,0x74,0x00,0x70,	// 37
	0x00,0x00,0x30,0x00,0x5C,0x00,0x74,0x00,0x64,	// 38
	0x00,0x00,0x0C,	// 39
	0x00,0x00,0x3C,0x00,0x42,	// 40
	0x00,0x00,0x42,0x00,0x3C,	// 41
	0x00,0x00,0x28,0x00,0x3C,0x00,0x28,	// 42
	0x00,0x00,0x10,0x00,0x10,0x00,0x7C,0x00,0x10,0x00,0x10,	// 43
	0x00,0x00,0xC0,	// 44
	0x00,0x00,0x10,0x00,0x10,	// 45
	0x00,0x00,0x40,	// 46
	0xE0,0x00,0x1C,	// 47
	0x00,0x00,0x7C,0x00,0x44,0x00,0x7C,	// 48
	0x00,0x00,0x44,0x00,0x7C,0x00,0x40,	// 49
	0x00,0x00,0x44,0x00,0x64,0x00,0x5C,	// 50
	0x00,0x00,0x44,0x00,0x54,0x00,0x6C,	// 51
	0x00,0x00,0x20,0x00,0x38,0x00,0x7C,	// 52
	0x00,0x00,0x5C,0x00,0x54,0x00,0x74,	// 53
	0x00,0x00,0x78,0x00,0x54,0x00,0x74,	// 54
	0x00,0x00,0x04,0x00,0x64,0x00,0x1C,	// 55
	0x00,0x00,0x6C,0x00,0x54,0x00,0x6C,	// 56
	0x00,0x00,0x5C,0x00,0x54,0x00,0x3C,	// 57
	0x00,0x00,0x48,	// 58
	0x00,0x00,0xC8,	// 59
	0x00,0x00,0x30,0x00,0x30,0x00,0x30,0x00,0x48,	// 60
	0x00,0x00,0x28,0x00,0x28,0x00,0x28,0x00,0x28,	// 61
	0x00,0x00,0x48,0x00,0x30,0x00,0x30,0x00,0x30,	// 62
	0x00,0x00,0x04,0x00,0x54,0x00,0x0C,	// 63
	0x00,0x00,0x78,0x00,0xCC,0x00,0xB4,0x00,0xB4,0x00,0x24,0x00,0x18,	// 64
	0x40,0x00,0x38,0x00,0x2C,0x00,0x38,0x00,0x40,	// 65
	0x00,0x00,0x7C,0x00,0x54,0x00,0x54,0x00,0x6C,	// 66
	0x00,0x00,0x38,0x00,0x44,0x00,0x44,0x00,0x44,	// 67
	0x00,0x00,0x7C,0x00,0x44,0x00,0x44,0x00,0x38,	// 68
	0x00,0x00,0x7C,0x00,0x54,0x00,0x54,	// 69
	0x00,0x00,0x7C,0x00,0x14,0x00,0x14,	// 70
	0x00,0x00,0x38,0x00,0x44,0x00,0x54,0x00,0x74,	// 71
	0x00,0x00,0x7C,0x00,0x10,0x00,0x10,0x00,0x7C,	// 72
	0x00,0x00,0x7C,	// 73
	0x80,0x00,0xFC,	// 74
	0x00,0x00,0x7C,0x00,0x38,0x00,0x64,0x00,0x40,	// 75
	0x00,0x00,0x7C,0x00,0x40,0x00,0x40,	// 76
	0x00,0x00,0x7C,0x00,0x0C,0x00,0x30,0x00,0x0C,0x00,0x7C,	// 77
	0x00,0x00,0x7C,0x00,0x1C,0x00,0x30,0x00,0x7C,	// 78
	0x00,0x00,0x38,0x00,0x44,0x00,0x44,0x00,0x38,	// 79
	0x00,0x00,0x7C,0x00,0x14,0x00,0x1C,	// 80
	0x00,0x00,0x38,0x00,0x44,0x00,0xC4,0x00,0x38,	// 81
	0x00,0x00,0x7C,0x00,0x14,0x00,0x6C,0x00,0x40,	// 82
	0x00,0x00,0x4C,0x00,0x54,0x00,0x54,	// 83
	0x04,0x00,0x04,0x00,0x7C,0x00,0x04,	// 84
	0x00,0x00,0x3C,0x00,0x40,0x00,0x40,0x00,0x3C,	// 85
	0x04,0x00,0x38,0x00,0x60,0x00,0x38,0x00,0x04,	// 86
	0x0C,0x00,0x70,0x00,0x1C,0x00,0x1C,0x00,0x70,0x00,0x0C,	// 87
	0x44,0x00,0x38,0x00,0x38,0x00,0x44,	// 88
	0x04,0x00,0x0C,0x00,0x70,0x00,0x0C,	// 89
	0x00,0x00,0x44,0x00,0x74,0x00,0x5C,0x00,0x44,	// 90
	0x00,0x00,0xFC,0x00,0x84,	// 91
	0x1C,0x00,0xE0,	// 92
	0x00,0x00,0x84,0x00,0xFC,	// 93
	0x00,0x00,0x08,0x00,0x04,0x00,0x04,0x00,0x08,	// 94
	0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,	// 95
	0x02,	// 96
	0x00,0x00,0x60,0x00,0x68,0x00,0x78,	// 97
	0x00,0x00,0x7E,0x00,0x48,0x00,0x78,	// 98
	0x00,0x00,0x30,0x00,0x48,0x00,0x48,	// 99
	0x00,0x00,0x78,0x00,0x48,0x00,0x7E,	// 100
	0x00,0x00,0x78,0x00,0x58,0x00,0x58,	// 101
	0x08,0x00,0x7E,	// 102
	0x00,0x00,0xF8,0x00,0xC8,0x00,0xF8,	// 103
	0x00,0x00,0x7E,0x00,0x08,0x00,0x78,	// 104
	0x00,0x00,0x7C,	// 105
	0x80,0x00,0xFC,	// 106
	0x00,0x00,0x7E,0x00,0x78,0x00,0x48,	// 107
	0x00,0x00,0x7E,	// 108
	0x00,0x00,0x78,0x00,0x08,0x00,0x78,0x00,0x08,0x00,0x78,	// 109
	0x00,0x00,0x78,0x00,0x08,0x00,0x78,	// 110
	0x00,0x00,0x78,0x00,0x48,0x00,0x78,	// 111
	0x00,0x00,0xF8,0x00,0x48,0x00,0x78,	// 112
	0x00,0x00,0x78,0x00,0x48,0x00,0xF8,	// 113
	0x00,0x00,0x78,0x00,0x08,	// 114
	0x00,0x00,0x58,0x00,0x58,0x00,0x68,	// 115
	0x00,0x00,0x7C,0x00,0x48,	// 116
	0x00,0x00,0x78,0x00,0x40,0x00,0x78,	// 117
	0x08,0x00,0x70,0x00,0x70,0x00,0x08,	// 118
	0x18,0x00,0x70,0x00,0x08,0x00,0x70,0x00,0x18,	// 119
	0x48,0x00,0x78,0x00,0x78,0x00,0x48,	// 120
	0x88,0x00,0xF0,0x00,0x30,0x00,0x08,	// 121
	0x00,0x00,0x48,0x00,0x78,0x00,0x58,	// 122
	0x00,0x00,0x10,0x00,0xEC,0x00,0x84,	// 123
	0x00,0x00,0xFC,0x01,	// 124
	0x00,0x00,0x84,0x00,0xEC,0x00,0x10,	// 125
	0x00,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x10,	// 126
	0xFC,0x00,0x84,0x00,0x84,0x00,0xFC,	// 127
	0xFC,0x00,0x84,0x00,0x84,0x00,0xFC,	// 128
	0xFC,0x00,0x84,0x00,0x84,0x00,0xFC,	// 129
	0xFC,0x00,0x84,0x00,0x84,0x00,0xFC,	// 130
	0xFC,0x00,0x84,0x00,0x84,0x00,0xFC,	// 131
	0xFC,0x00,0x84,0x00,0x84,0x00,0xFC,	// 132
	0xFC,0x00,0x84,0x00,0x84,0x00,0xFC,	// 133
	0xFC,0x00,0x84,0x00,0x84,0x00,0xFC,	// 134
	0xFC,0x00,0x84,0x00,0x84,0x00,0xFC,	// 135
	0xFC,0x00,0x84,0x00,0x84,0x00,0xFC,	// 136
	0xFC,0x00,0x84,0x00,0x84,0x00,0xFC,	// 137
	0xFC,0x00,0x84,0x00,0x84,0x00,0xFC,	// 138
	0xFC,0x00,0x84,0x00,0x84,0x00,0xFC,	// 139
	0xFC,0x00,0x84,0x00,0x84,0x00,0xFC,	// 140
	0xFC,0x00,0x84,0x00,0x84,0x00,0xFC,	// 141
	0xFC,0x00,0x84,0x00,0x84,0x00,0xFC,	// 142
	0xFC,0x00,0x84,0x00,0x84,0x00,0xFC,	// 143
	0xFC,0x00,0x84,0x00,0x84,0x00,0xFC,	// 144
	0xFC,0x00,0x84,0x00,0x84,0x00,0xFC,	// 145
	0xFC,0x00,0x84,0x00,0x84,0x00,0xFC,	// 146
	0xFC,0x00,0x84,0x00,0x84,0x00,0xFC,	// 147
	0xFC,0x00,0x84,0x00,0x84,0x00,0xFC,	// 148
	0xFC,0x00,0x84,0x00,0x84,0x00,0xFC,	// 149
	0xFC,0x00,0x84,0x00,0x84,0x00,0xFC,	// 150
	0xFC,0x00,0x84,0x00,0x84,0x00,0xFC,	// 151
	0xFC,0x00,0x84,0x00,0x84,0x00,0xFC,	// 152
	0xFC,0x00,0x84,0x00,0x84,0x00,0xFC,	// 153
	0xFC,0x00,0x84,0x00,0x84,0x00,0xFC,	// 154
	0xFC,0x00,0x84,0x00,0x84,0x00,0xFC,	// 155
	0xFC,0x00,0x84,0x00,0x84,0x00,0xFC,	// 156
	0xFC,0x00,0x84,0x00,0x84,0x00,0xFC,	// 157
	0xFC,0x00,0x84,0x00,0x84,0x00,0xFC,	// 158
	0xFC,0x00,0x84,0x00,0x84,0x00,0xFC,	// 159
	0x00,0x00,0xE8,	// 161
	0x00,0x00,0x78,0x00,0xFC,0x00,0x48,	// 162
	0x50,0x00,0x7C,0x00,0x54,0x00,0x44,	// 163
	0x00,0x00,0x38,0x00,0x28,0x00,0x38,	// 164
	0x00,0x00,0x2C,0x00,0x70,0x00,0x2C,	// 165
	0x00,0x00,0xDC,0x01,	// 166
	0x00,0x00,0xBC,0x00,0xB4,0x00,0xF4,	// 167
	0x00,0x00,0x04,0x00,0x00,0x00,0x04,	// 168
	0x00,0x00,0x38,0x00,0x44,0x00,0x54,0x00,0x44,0x00,0x38,	// 169
	0x00,0x00,0x58,0x00,0x5C,	// 170
	0x00,0x00,0x10,0x00,0x38,0x00,0x10,	// 171
	0x00,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x30,	// 172
	0x00,0x00,0x10,0x00,0x10,	// 173
	0x00,0x00,0x38,0x00,0x44,0x00,0x74,0x00,0x44,0x00,0x38,	// 174
	0x00,0x00,0x04,0x00,0x04,	// 175
	0x00,0x00,0x0C,0x00,0x0C,	// 176
	0x00,0x00,0x50,0x00,0x50,0x00,0x78,0x00,0x50,0x00,0x50,	// 177
	0x00,0x00,0x14,0x00,0x1C,	// 178
	0x00,0x00,0x1C,0x00,0x14,	// 179
	0x00,0x00,0x02,	// 180
	0x00,0x00,0xF8,0x00,0x40,0x00,0x78,	// 181
	0x00,0x00,0xFC,0x00,0x04,0x00,0xFC,	// 182
	0x00,0x00,0x10,	// 183
	0x00,0x00,0x80,	// 184
	0x00,0x00,0x14,0x00,0x1C,	// 185
	0x00,0x00,0x5C,0x00,0x54,	// 186
	0x00,0x00,0x38,0x00,0x10,0x00,0x38,	// 187
	0x00,0x00,0x14,0x00,0x5C,0x00,0x30,0x00,0x18,0x00,0x64,0x00,0x70,	// 188
	0x00,0x00,0x14,0x00,0x5C,0x00,0x30,0x00,0x18,0x00,0x54,0x00,0x70,	// 189
	0x00,0x00,0x1C,0x00,0x54,0x00,0x30,0x00,0x18,0x00,0x64,0x00,0x70,	// 190
	0x00,0x00,0xC0,0x00,0xA8,0x00,0x80,	// 191
	0x40,0x00,0x3A,0x00,0x2E,0x00,0x38,0x00,0x40,	// 192
	0x40,0x00,0x38,0x00,0x2E,0x00,0x3A,0x00,0x40,	// 193
	0x40,0x00,0x38,0x00,0x2C,0x00,0x38,0x00,0x40,	// 194
	0x40,0x00,0x38,0x00,0x2E,0x00,0x38,0x00,0x40,	// 195
	0x40,0x00,0x3A,0x00,0x2C,0x00,0x3A,0x00,0x40,	// 196
	0x40,0x00,0x3A,0x00,0x2E,0x00,0x3A,0x00,0x40,	// 197
	0x40,0x00,0x38,0x00,0x2C,0x00,0x7C,0x00,0x54,0x00,0x54,	// 198
	0x00,0x00,0x38,0x00,0xC4,0x00,0x44,0x00,0x44,	// 199
	0x00,0x00,0x7E,0x00,0x56,0x00,0x54,	// 200
	0x00,0x00,0x7C,0x00,0x56,0x00,0x56,	// 201
	0x00,0x00,0x7E,0x00,0x56,0x00,0x54,	// 202
	0x00,0x00,0x7E,0x00,0x54,0x00,0x56,	// 203
	0x02,0x00,0x7E,	// 204
	0x00,0x00,0x7E,	// 205
	0x02,0x00,0x7E,	// 206
	0x02,0x00,0x7C,	// 207
	0x10,0x00,0x7C,0x00,0x54,0x00,0x44,0x00,0x38,	// 208
	0x00,0x00,0x7C,0x00,0x1E,0x00,0x32,0x00,0x7C,	// 209
	0x00,0x00,0x38,0x00,0x46,0x00,0x46,0x00,0x38,	// 210
	0x00,0x00,0x38,0x00,0x44,0x00,0x46,0x00,0x3A,	// 211
	0x00,0x00,0x38,0x00,0x46,0x00,0x46,0x00,0x38,	// 212
	0x00,0x00,0x38,0x00,0x46,0x00,0x46,0x00,0x38,	// 213
	0x00,0x00,0x3A,0x00,0x44,0x00,0x44,0x00,0x3A,	// 214
	0x00,0x00,0x48,0x00,0x30,0x00,0x30,0x00,0x48,	// 215
	0x00,0x00,0x78,0x00,0x54,0x00,0x54,0x00,0x3C,	// 216
	0x00,0x00,0x3E,0x00,0x42,0x00,0x40,0x00,0x3C,	// 217
	0x00,0x00,0x3C,0x00,0x42,0x00,0x42,0x00,0x3C,	// 218
	0x00,0x00,0x3C,0x00,0x42,0x00,0x42,0x00,0x3C,	// 219
	0x00,0x00,0x3E,0x00,0x40,0x00,0x40,0x00,0x3E,	// 220
	0x04,0x00,0x0C,0x00,0x72,0x00,0x0E,	// 221
	0x00,0x00,0x7C,0x00,0x28,0x00,0x38,	// 222
	0x00,0x00,0x7E,0x00,0x1A,0x00,0x66,	// 223
	0x02,0x00,0x60,0x00,0x68,0x00,0x78,	// 224
	0x00,0x00,0x62,0x00,0x68,0x00,0x78,	// 225
	0x00,0x00,0x60,0x00,0x68,0x00,0x78,	// 226
	0x00,0x00,0x6C,0x00,0x6C,0x00,0x7C,	// 227
	0x00,0x00,0x64,0x00,0x68,0x00,0x7C,	// 228
	0x00,0x00,0x60,0x00,0x6E,0x00,0x7E,	// 229
	0x00,0x00,0x60,0x00,0x68,0x00,0x30,0x00,0x58,0x00,0x58,	// 230
	0x00,0x00,0xB0,0x00,0x48,0x00,0x48,	// 231
	0x02,0x00,0x78,0x00,0x58,0x00,0x58,	// 232
	0x00,0x00,0x7A,0x00,0x58,0x00,0x58,	// 233
	0x00,0x00,0x7A,0x00,0x5A,0x00,0x58,	// 234
	0x00,0x00,0x7C,0x00,0x58,0x00,0x5C,	// 235
	0x00,0x00,0x78,	// 236
	0x02,0x00,0x78,	// 237
	0x02,0x00,0x7A,	// 238
	0x04,0x00,0x78,	// 239
	0x00,0x00,0x78,0x00,0x4C,0x00,0x78,	// 240
	0x00,0x00,0x7C,0x00,0x0C,0x00,0x7C,	// 241
	0x02,0x00,0x78,0x00,0x48,0x00,0x78,	// 242
	0x00,0x00,0x7A,0x00,0x48,0x00,0x78,	// 243
	0x00,0x00,0x78,0x00,0x48,0x00,0x78,	// 244
	0x00,0x00,0x7C,0x00,0x4C,0x00,0x7C,	// 245
	0x00,0x00,0x7C,0x00,0x48,0x00,0x7C,	// 246
	0x00,0x00,0x10,0x00,0x10,0x00,0x54,0x00,0x10,0x00,0x10,	// 247
	0x00,0x00,0x78,0x00,0x68,0x00,0x78,	// 248
	0x02,0x00,0x78,0x00,0x40,0x00,0x78,	// 249
	0x00,0x00,0x7A,0x00,0x40,0x00,0x78,	// 250
	0x00,0x00,0x78,0x00,0x40,0x00,0x78,	// 251
	0x00,0x00,0x7C,0x00,0x40,0x00,0x7C,	// 252
	0x88,0x00,0xF2,0x00,0x30,0x00,0x08,	// 253
	0x00,0x00,0xFE,0x00,0x48,0x00,0x78,	// 254
	0x88,0x00,0xF4,0x00,0x34,0x00,0x08	// 255
};

================================================
FILE: examples/SSD1306FontTryout/Dialog_plain_8.h
================================================
// Created by http://oleddisplay.squix.ch/ Consider a donation
// In case of problems make sure that you are using the font file with the correct version!
const char Dialog_plain_8[] PROGMEM = {
	0x08, // Width: 8
	0x0A, // Height: 10
	0x20, // First Char: 32
	0xE0, // Numbers of Chars: 224

	// Jump Table:
	0xFF, 0xFF, 0x00, 0x03,  // 32:65535
	0x00, 0x00, 0x03, 0x03,  // 33:0
	0x00, 0x03, 0x07, 0x04,  // 34:3
	0x00, 0x0A, 0x0B, 0x07,  // 35:10
	0x00, 0x15, 0x09, 0x05,  // 36:21
	0x00, 0x1E, 0x0F, 0x08,  // 37:30
	0x00, 0x2D, 0x0B, 0x06,  // 38:45
	0x00, 0x38, 0x03, 0x02,  // 39:56
	0x00, 0x3B, 0x05, 0x03,  // 40:59
	0x00, 0x40, 0x05, 0x03,  // 41:64
	0x00, 0x45, 0x07, 0x04,  // 42:69
	0x00, 0x4C, 0x0B, 0x07,  // 43:76
	0x00, 0x57, 0x04, 0x03,  // 44:87
	0x00, 0x5B, 0x05, 0x03,  // 45:91
	0x00, 0x60, 0x03, 0x03,  // 46:96
	0x00, 0x63, 0x05, 0x03,  // 47:99
	0x00, 0x68, 0x09, 0x05,  // 48:104
	0x00, 0x71, 0x07, 0x05,  // 49:113
	0x00, 0x78, 0x09, 0x05,  // 50:120
	0x00, 0x81, 0x09, 0x05,  // 51:129
	0x00, 0x8A, 0x09, 0x05,  // 52:138
	0x00, 0x93, 0x09, 0x05,  // 53:147
	0x00, 0x9C, 0x09, 0x05,  // 54:156
	0x00, 0xA5, 0x09, 0x05,  // 55:165
	0x00, 0xAE, 0x09, 0x05,  // 56:174
	0x00, 0xB7, 0x09, 0x05,  // 57:183
	0x00, 0xC0, 0x03, 0x03,  // 58:192
	0x00, 0xC3, 0x04, 0x03,  // 59:195
	0x00, 0xC7, 0x0B, 0x07,  // 60:199
	0x00, 0xD2, 0x0B, 0x07,  // 61:210
	0x00, 0xDD, 0x0B, 0x07,  // 62:221
	0x00, 0xE8, 0x07, 0x04,  // 63:232
	0x00, 0xEF, 0x0F, 0x08,  // 64:239
	0x00, 0xFE, 0x09, 0x05,  // 65:254
	0x01, 0x07, 0x09, 0x05,  // 66:263
	0x01, 0x10, 0x0B, 0x06,  // 67:272
	0x01, 0x1B, 0x0B, 0x06,  // 68:283
	0x01, 0x26, 0x09, 0x05,  // 69:294
	0x01, 0x2F, 0x07, 0x05,  // 70:303
	0x01, 0x36, 0x0B, 0x06,  // 71:310
	0x01, 0x41, 0x09, 0x06,  // 72:321
	0x01, 0x4A, 0x03, 0x02,  // 73:330
	0x01, 0x4D, 0x04, 0x02,  // 74:333
	0x01, 0x51, 0x09, 0x05,  // 75:337
	0x01, 0x5A, 0x07, 0x04,  // 76:346
	0x01, 0x61, 0x0B, 0x07,  // 77:353
	0x01, 0x6C, 0x09, 0x06,  // 78:364
	0x01, 0x75, 0x0B, 0x06,  // 79:373
	0x01, 0x80, 0x09, 0x05,  // 80:384
	0x01, 0x89, 0x0B, 0x06,  // 81:393
	0x01, 0x94, 0x0B, 0x06,  // 82:404
	0x01, 0x9F, 0x09, 0x05,  // 83:415
	0x01, 0xA8, 0x09, 0x05,  // 84:424
	0x01, 0xB1, 0x09, 0x06,  // 85:433
	0x01, 0xBA, 0x09, 0x05,  // 86:442
	0x01, 0xC3, 0x0D, 0x08,  // 87:451
	0x01, 0xD0, 0x09, 0x05,  // 88:464
	0x01, 0xD9, 0x09, 0x05,  // 89:473
	0x01, 0xE2, 0x09, 0x05,  // 90:482
	0x01, 0xEB, 0x06, 0x03,  // 91:491
	0x01, 0xF1, 0x06, 0x03,  // 92:497
	0x01, 0xF7, 0x06, 0x03,  // 93:503
	0x01, 0xFD, 0x09, 0x07,  // 94:509
	0x02, 0x06, 0x08, 0x04,  // 95:518
	0x02, 0x0E, 0x03, 0x04,  // 96:526
	0x02, 0x11, 0x09, 0x05,  // 97:529
	0x02, 0x1A, 0x09, 0x05,  // 98:538
	0x02, 0x23, 0x07, 0x04,  // 99:547
	0x02, 0x2A, 0x09, 0x05,  // 100:554
	0x02, 0x33, 0x09, 0x05,  // 101:563
	0x02, 0x3C, 0x05, 0x03,  // 102:572
	0x02, 0x41, 0x0A, 0x05,  // 103:577
	0x02, 0x4B, 0x09, 0x05,  // 104:587
	0x02, 0x54, 0x03, 0x02,  // 105:596
	0x02, 0x57, 0x04, 0x02,  // 106:599
	0x02, 0x5B, 0x07, 0x05,  // 107:603
	0x02, 0x62, 0x03, 0x02,  // 108:610
	0x02, 0x65, 0x0F, 0x08,  // 109:613
	0x02, 0x74, 0x09, 0x05,  // 110:628
	0x02, 0x7D, 0x09, 0x05,  // 111:637
	0x02, 0x86, 0x09, 0x05,  // 112:646
	0x02, 0x8F, 0x0A, 0x05,  // 113:655
	0x02, 0x99, 0x05, 0x03,  // 114:665
	0x02, 0x9E, 0x07, 0x04,  // 115:670
	0x02, 0xA5, 0x05, 0x03,  // 116:677
	0x02, 0xAA, 0x09, 0x05,  // 117:682
	0x02, 0xB3, 0x07, 0x05,  // 118:691
	0x02, 0xBA, 0x0B, 0x07,  // 119:698
	0x02, 0xC5, 0x07, 0x05,  // 120:709
	0x02, 0xCC, 0x09, 0x05,  // 121:716
	0x02, 0xD5, 0x07, 0x04,  // 122:725
	0x02, 0xDC, 0x08, 0x05,  // 123:732
	0x02, 0xE4, 0x04, 0x03,  // 124:740
	0x02, 0xE8, 0x07, 0x05,  // 125:744
	0x02, 0xEF, 0x0B, 0x07,  // 126:751
	0x02, 0xFA, 0x08, 0x05,  // 127:762
	0x03, 0x02, 0x08, 0x05,  // 128:770
	0x03, 0x0A, 0x08, 0x05,  // 129:778
	0x03, 0x12, 0x08, 0x05,  // 130:786
	0x03, 0x1A, 0x08, 0x05,  // 131:794
	0x03, 0x22, 0x08, 0x05,  // 132:802
	0x03, 0x2A, 0x08, 0x05,  // 133:810
	0x03, 0x32, 0x08, 0x05,  // 134:818
	0x03, 0x3A, 0x08, 0x05,  // 135:826
	0x03, 0x42, 0x08, 0x05,  // 136:834
	0x03, 0x4A, 0x08, 0x05,  // 137:842
	0x03, 0x52, 0x08, 0x05,  // 138:850
	0x03, 0x5A, 0x08, 0x05,  // 139:858
	0x03, 0x62, 0x08, 0x05,  // 140:866
	0x03, 0x6A, 0x08, 0x05,  // 141:874
	0x03, 0x72, 0x08, 0x05,  // 142:882
	0x03, 0x7A, 0x08, 0x05,  // 143:890
	0x03, 0x82, 0x08, 0x05,  // 144:898
	0x03, 0x8A, 0x08, 0x05,  // 145:906
	0x03, 0x92, 0x08, 0x05,  // 146:914
	0x03, 0x9A, 0x08, 0x05,  // 147:922
	0x03, 0xA2, 0x08, 0x05,  // 148:930
	0x03, 0xAA, 0x08, 0x05,  // 149:938
	0x03, 0xB2, 0x08, 0x05,  // 150:946
	0x03, 0xBA, 0x08, 0x05,  // 151:954
	0x03, 0xC2, 0x08, 0x05,  // 152:962
	0x03, 0xCA, 0x08, 0x05,  // 153:970
	0x03, 0xD2, 0x08, 0x05,  // 154:978
	0x03, 0xDA, 0x08, 0x05,  // 155:986
	0x03, 0xE2, 0x08, 0x05,  // 156:994
	0x03, 0xEA, 0x08, 0x05,  // 157:1002
	0x03, 0xF2, 0x08, 0x05,  // 158:1010
	0x03, 0xFA, 0x08, 0x05,  // 159:1018
	0xFF, 0xFF, 0x00, 0x03,  // 160:65535
	0x04, 0x02, 0x04, 0x03,  // 161:1026
	0x04, 0x06, 0x07, 0x05,  // 162:1030
	0x04, 0x0D, 0x07, 0x05,  // 163:1037
	0x04, 0x14, 0x09, 0x05,  // 164:1044
	0x04, 0x1D, 0x09, 0x05,  // 165:1053
	0x04, 0x26, 0x04, 0x03,  // 166:1062
	0x04, 0x2A, 0x08, 0x04,  // 167:1066
	0x04, 0x32, 0x07, 0x04,  // 168:1074
	0x04, 0x39, 0x0D, 0x08,  // 169:1081
	0x04, 0x46, 0x07, 0x04,  // 170:1094
	0x04, 0x4D, 0x09, 0x05,  // 171:1101
	0x04, 0x56, 0x0B, 0x07,  // 172:1110
	0x04, 0x61, 0x05, 0x03,  // 173:1121
	0x04, 0x66, 0x0D, 0x08,  // 174:1126
	0x04, 0x73, 0x05, 0x04,  // 175:1139
	0x04, 0x78, 0x05, 0x04,  // 176:1144
	0x04, 0x7D, 0x0B, 0x07,  // 177:1149
	0x04, 0x88, 0x05, 0x03,  // 178:1160
	0x04, 0x8D, 0x05, 0x03,  // 179:1165
	0x04, 0x92, 0x03, 0x04,  // 180:1170
	0x04, 0x95, 0x09, 0x05,  // 181:1173
	0x04, 0x9E, 0x0A, 0x05,  // 182:1182
	0x04, 0xA8, 0x03, 0x03,  // 183:1192
	0x04, 0xAB, 0x06, 0x04,  // 184:1195
	0x04, 0xB1, 0x05, 0x03,  // 185:1201
	0x04, 0xB6, 0x07, 0x04,  // 186:1206
	0x04, 0xBD, 0x09, 0x05,  // 187:1213
	0x04, 0xC6, 0x0F, 0x08,  // 188:1222
	0x04, 0xD5, 0x0F, 0x08,  // 189:1237
	0x04, 0xE4, 0x0F, 0x08,  // 190:1252
	0x04, 0xF3, 0x08, 0x04,  // 191:1267
	0x04, 0xFB, 0x09, 0x05,  // 192:1275
	0x05, 0x04, 0x09, 0x05,  // 193:1284
	0x05, 0x0D, 0x09, 0x05,  // 194:1293
	0x05, 0x16, 0x09, 0x05,  // 195:1302
	0x05, 0x1F, 0x09, 0x05,  // 196:1311
	0x05, 0x28, 0x09, 0x05,  // 197:1320
	0x05, 0x31, 0x0D, 0x08,  // 198:1329
	0x05, 0x3E, 0x0B, 0x06,  // 199:1342
	0x05, 0x49, 0x09, 0x05,  // 200:1353
	0x05, 0x52, 0x09, 0x05,  // 201:1362
	0x05, 0x5B, 0x09, 0x05,  // 202:1371
	0x05, 0x64, 0x09, 0x05,  // 203:1380
	0x05, 0x6D, 0x03, 0x02,  // 204:1389
	0x05, 0x70, 0x03, 0x02,  // 205:1392
	0x05, 0x73, 0x03, 0x02,  // 206:1395
	0x05, 0x76, 0x03, 0x02,  // 207:1398
	0x05, 0x79, 0x0B, 0x06,  // 208:1401
	0x05, 0x84, 0x09, 0x06,  // 209:1412
	0x05, 0x8D, 0x0B, 0x06,  // 210:1421
	0x05, 0x98, 0x0B, 0x06,  // 211:1432
	0x05, 0xA3, 0x0B, 0x06,  // 212:1443
	0x05, 0xAE, 0x0B, 0x06,  // 213:1454
	0x05, 0xB9, 0x0B, 0x06,  // 214:1465
	0x05, 0xC4, 0x0B, 0x07,  // 215:1476
	0x05, 0xCF, 0x0B, 0x06,  // 216:1487
	0x05, 0xDA, 0x09, 0x06,  // 217:1498
	0x05, 0xE3, 0x09, 0x06,  // 218:1507
	0x05, 0xEC, 0x09, 0x06,  // 219:1516
	0x05, 0xF5, 0x09, 0x06,  // 220:1525
	0x05, 0xFE, 0x09, 0x05,  // 221:1534
	0x06, 0x07, 0x09, 0x05,  // 222:1543
	0x06, 0x10, 0x09, 0x05,  // 223:1552
	0x06, 0x19, 0x09, 0x05,  // 224:1561
	0x06, 0x22, 0x09, 0x05,  // 225:1570
	0x06, 0x2B, 0x09, 0x05,  // 226:1579
	0x06, 0x34, 0x09, 0x05,  // 227:1588
	0x06, 0x3D, 0x09, 0x05,  // 228:1597
	0x06, 0x46, 0x09, 0x05,  // 229:1606
	0x06, 0x4F, 0x0F, 0x08,  // 230:1615
	0x06, 0x5E, 0x08, 0x04,  // 231:1630
	0x06, 0x66, 0x09, 0x05,  // 232:1638
	0x06, 0x6F, 0x09, 0x05,  // 233:1647
	0x06, 0x78, 0x09, 0x05,  // 234:1656
	0x06, 0x81, 0x09, 0x05,  // 235:1665
	0x06, 0x8A, 0x03, 0x02,  // 236:1674
	0x06, 0x8D, 0x03, 0x02,  // 237:1677
	0x06, 0x90, 0x03, 0x02,  // 238:1680
	0x06, 0x93, 0x03, 0x02,  // 239:1683
	0x06, 0x96, 0x09, 0x05,  // 240:1686
	0x06, 0x9F, 0x09, 0x05,  // 241:1695
	0x06, 0xA8, 0x09, 0x05,  // 242:1704
	0x06, 0xB1, 0x09, 0x05,  // 243:1713
	0x06, 0xBA, 0x09, 0x05,  // 244:1722
	0x06, 0xC3, 0x09, 0x05,  // 245:1731
	0x06, 0xCC, 0x09, 0x05,  // 246:1740
	0x06, 0xD5, 0x0B, 0x07,  // 247:1749
	0x06, 0xE0, 0x09, 0x05,  // 248:1760
	0x06, 0xE9, 0x09, 0x05,  // 249:1769
	0x06, 0xF2, 0x09, 0x05,  // 250:1778
	0x06, 0xFB, 0x09, 0x05,  // 251:1787
	0x07, 0x04, 0x09, 0x05,  // 252:1796
	0x07, 0x0D, 0x09, 0x05,  // 253:1805
	0x07, 0x16, 0x09, 0x05,  // 254:1814
	0x07, 0x1F, 0x09, 0x05,  // 255:1823

	// Font Data:
	0x00,0x00,0xBC,	// 33
	0x00,0x00,0x0C,0x00,0x00,0x00,0x0C,	// 34
	0x00,0x00,0xA8,0x00,0x7C,0x00,0xEA,0x00,0x3E,0x00,0x28,	// 35
	0x00,0x00,0x98,0x00,0xA8,0x00,0xFC,0x01,0xA8,	// 36
	0x00,0x00,0x1C,0x00,0x14,0x00,0xDC,0x00,0x30,0x00,0xEC,0x00,0xA0,0x00,0xE0,	// 37
	0x00,0x00,0x60,0x00,0xBC,0x00,0xF4,0x00,0xC4,0x00,0xA0,	// 38
	0x00,0x00,0x0C,	// 39
	0x00,0x00,0x7C,0x00,0x82,	// 40
	0x00,0x00,0x82,0x00,0x7C,	// 41
	0x24,0x00,0x18,0x00,0x3C,0x00,0x18,	// 42
	0x00,0x00,0x20,0x00,0x20,0x00,0xF8,0x00,0x20,0x00,0x20,	// 43
	0x00,0x00,0x80,0x01,	// 44
	0x00,0x00,0x20,0x00,0x20,	// 45
	0x00,0x00,0x80,	// 46
	0x80,0x01,0x70,0x00,0x0C,	// 47
	0x00,0x00,0x78,0x00,0x84,0x00,0x84,0x00,0x78,	// 48
	0x00,0x00,0x84,0x00,0xFC,0x00,0x80,	// 49
	0x00,0x00,0x84,0x00,0xC4,0x00,0xA4,0x00,0x98,	// 50
	0x00,0x00,0x84,0x00,0xA4,0x00,0xA4,0x00,0xD8,	// 51
	0x00,0x00,0x60,0x00,0x58,0x00,0xFC,0x00,0x40,	// 52
	0x00,0x00,0x9C,0x00,0x94,0x00,0x94,0x00,0x64,	// 53
	0x00,0x00,0x78,0x00,0xAC,0x00,0xA4,0x00,0xE4,	// 54
	0x00,0x00,0x04,0x00,0x84,0x00,0x74,0x00,0x0C,	// 55
	0x00,0x00,0xD8,0x00,0xA4,0x00,0xA4,0x00,0xD8,	// 56
	0x00,0x00,0x9C,0x00,0x94,0x00,0xD4,0x00,0x78,	// 57
	0x00,0x00,0x90,	// 58
	0x00,0x00,0x90,0x01,	// 59
	0x00,0x00,0x20,0x00,0x30,0x00,0x30,0x00,0x30,0x00,0x48,	// 60
	0x00,0x00,0x50,0x00,0x50,0x00,0x50,0x00,0x50,0x00,0x50,	// 61
	0x00,0x00,0x48,0x00,0x30,0x00,0x30,0x00,0x30,0x00,0x20,	// 62
	0x00,0x00,0x04,0x00,0xB4,0x00,0x0C,	// 63
	0x00,0x00,0x70,0x00,0x88,0x00,0x74,0x01,0x54,0x01,0x74,0x01,0x4C,0x00,0x38,	// 64
	0x80,0x00,0x70,0x00,0x4C,0x00,0x70,0x00,0x80,	// 65
	0x00,0x00,0xFC,0x00,0xA4,0x00,0xA4,0x00,0xDC,	// 66
	0x00,0x00,0x78,0x00,0xCC,0x00,0x84,0x00,0x84,0x00,0x88,	// 67
	0x00,0x00,0xFC,0x00,0x84,0x00,0x84,0x00,0x84,0x00,0x78,	// 68
	0x00,0x00,0xFC,0x00,0xA4,0x00,0xA4,0x00,0xA4,	// 69
	0x00,0x00,0xFC,0x00,0x24,0x00,0x24,	// 70
	0x00,0x00,0x78,0x00,0x8C,0x00,0x84,0x00,0x94,0x00,0x78,	// 71
	0x00,0x00,0xFC,0x00,0x20,0x00,0x20,0x00,0xFC,	// 72
	0x00,0x00,0xFC,	// 73
	0x00,0x02,0xFC,0x03,	// 74
	0x00,0x00,0xFC,0x00,0x30,0x00,0x68,0x00,0xC4,	// 75
	0x00,0x00,0xFC,0x00,0x80,0x00,0x80,	// 76
	0x00,0x00,0xFC,0x00,0x1C,0x00,0x70,0x00,0x1C,0x00,0xFC,	// 77
	0x00,0x00,0xFC,0x00,0x18,0x00,0x60,0x00,0xFC,	// 78
	0x00,0x00,0x78,0x00,0x84,0x00,0x84,0x00,0x84,0x00,0x78,	// 79
	0x00,0x00,0xFC,0x00,0x14,0x00,0x14,0x00,0x1C,	// 80
	0x00,0x00,0x78,0x00,0x84,0x00,0x84,0x00,0x84,0x01,0x78,	// 81
	0x00,0x00,0xFC,0x00,0x14,0x00,0x34,0x00,0x6C,0x00,0x80,	// 82
	0x00,0x00,0x98,0x00,0x94,0x00,0xB4,0x00,0xE4,	// 83
	0x04,0x00,0x04,0x00,0xFC,0x00,0x04,0x00,0x04,	// 84
	0x00,0x00,0x7C,0x00,0x80,0x00,0x80,0x00,0x7C,	// 85
	0x04,0x00,0x38,0x00,0xC0,0x00,0x38,0x00,0x04,	// 86
	0x0C,0x00,0xF0,0x00,0x78,0x00,0x04,0x00,0x78,0x00,0xF0,0x00,0x0C,	// 87
	0x84,0x00,0x4C,0x00,0x30,0x00,0x4C,0x00,0x84,	// 88
	0x04,0x00,0x0C,0x00,0xF0,0x00,0x0C,0x00,0x04,	// 89
	0x00,0x00,0x84,0x00,0xE4,0x00,0xB4,0x00,0x8C,	// 90
	0x00,0x00,0xFC,0x01,0x04,0x01,	// 91
	0x0C,0x00,0x70,0x00,0x80,0x01,	// 92
	0x00,0x00,0x04,0x01,0xFC,0x01,	// 93
	0x00,0x00,0x08,0x00,0x08,0x00,0x04,0x00,0x08,	// 94
	0x00,0x02,0x00,0x02,0x00,0x02,0x00,0x02,	// 95
	0x00,0x00,0x04,	// 96
	0x00,0x00,0xE0,0x00,0xB0,0x00,0xB0,0x00,0xF0,	// 97
	0x00,0x00,0xFE,0x00,0x90,0x00,0x90,0x00,0x60,	// 98
	0x00,0x00,0x60,0x00,0x90,0x00,0x90,	// 99
	0x00,0x00,0x60,0x00,0x90,0x00,0x90,0x00,0xFE,	// 100
	0x00,0x00,0x60,0x00,0xB0,0x00,0xB0,0x00,0xB0,	// 101
	0x10,0x00,0xFE,0x00,0x12,	// 102
	0x00,0x00,0x60,0x00,0x90,0x02,0x90,0x02,0xF0,0x01,	// 103
	0x00,0x00,0xFE,0x00,0x10,0x00,0x10,0x00,0xF0,	// 104
	0x00,0x00,0xF4,	// 105
	0x00,0x02,0xF4,0x03,	// 106
	0x00,0x00,0xFE,0x00,0x60,0x00,0x90,	// 107
	0x00,0x00,0xFE,	// 108
	0x00,0x00,0xF0,0x00,0x10,0x00,0x10,0x00,0xF0,0x00,0x10,0x00,0x10,0x00,0xF0,	// 109
	0x00,0x00,0xF0,0x00,0x10,0x00,0x10,0x00,0xF0,	// 110
	0x00,0x00,0x60,0x00,0x90,0x00,0x90,0x00,0x60,	// 111
	0x00,0x00,0xF0,0x03,0x90,0x00,0x90,0x00,0x60,	// 112
	0x00,0x00,0x60,0x00,0x90,0x00,0x90,0x00,0xF0,0x03,	// 113
	0x00,0x00,0xF0,0x00,0x10,	// 114
	0x00,0x00,0xB0,0x00,0xB0,0x00,0xD0,	// 115
	0x10,0x00,0xF8,0x00,0x90,	// 116
	0x00,0x00,0xF0,0x00,0x80,0x00,0x80,0x00,0xF0,	// 117
	0x10,0x00,0xE0,0x00,0xE0,0x00,0x10,	// 118
	0x30,0x00,0xC0,0x00,0x30,0x00,0x30,0x00,0xC0,0x00,0x30,	// 119
	0x90,0x00,0xF0,0x00,0xF0,0x00,0x90,	// 120
	0x00,0x00,0x10,0x02,0xE0,0x03,0x60,0x00,0x10,	// 121
	0x00,0x00,0x90,0x00,0xD0,0x00,0xF0,	// 122
	0x00,0x00,0x20,0x00,0xDC,0x01,0x04,0x01,	// 123
	0x00,0x00,0xFC,0x03,	// 124
	0x00,0x00,0x04,0x01,0xDC,0x01,0x20,	// 125
	0x00,0x00,0x20,0x00,0x20,0x00,0x60,0x00,0x40,0x00,0x40,	// 126
	0xFC,0x01,0x04,0x01,0x04,0x01,0xFC,0x01,	// 127
	0xFC,0x01,0x04,0x01,0x04,0x01,0xFC,0x01,	// 128
	0xFC,0x01,0x04,0x01,0x04,0x01,0xFC,0x01,	// 129
	0xFC,0x01,0x04,0x01,0x04,0x01,0xFC,0x01,	// 130
	0xFC,0x01,0x04,0x01,0x04,0x01,0xFC,0x01,	// 131
	0xFC,0x01,0x04,0x01,0x04,0x01,0xFC,0x01,	// 132
	0xFC,0x01,0x04,0x01,0x04,0x01,0xFC,0x01,	// 133
	0xFC,0x01,0x04,0x01,0x04,0x01,0xFC,0x01,	// 134
	0xFC,0x01,0x04,0x01,0x04,0x01,0xFC,0x01,	// 135
	0xFC,0x01,0x04,0x01,0x04,0x01,0xFC,0x01,	// 136
	0xFC,0x01,0x04,0x01,0x04,0x01,0xFC,0x01,	// 137
	0xFC,0x01,0x04,0x01,0x04,0x01,0xFC,0x01,	// 138
	0xFC,0x01,0x04,0x01,0x04,0x01,0xFC,0x01,	// 139
	0xFC,0x01,0x04,0x01,0x04,0x01,0xFC,0x01,	// 140
	0xFC,0x01,0x04,0x01,0x04,0x01,0xFC,0x01,	// 141
	0xFC,0x01,0x04,0x01,0x04,0x01,0xFC,0x01,	// 142
	0xFC,0x01,0x04,0x01,0x04,0x01,0xFC,0x01,	// 143
	0xFC,0x01,0x04,0x01,0x04,0x01,0xFC,0x01,	// 144
	0xFC,0x01,0x04,0x01,0x04,0x01,0xFC,0x01,	// 145
	0xFC,0x01,0x04,0x01,0x04,0x01,0xFC,0x01,	// 146
	0xFC,0x01,0x04,0x01,0x04,0x01,0xFC,0x01,	// 147
	0xFC,0x01,0x04,0x01,0x04,0x01,0xFC,0x01,	// 148
	0xFC,0x01,0x04,0x01,0x04,0x01,0xFC,0x01,	// 149
	0xFC,0x01,0x04,0x01,0x04,0x01,0xFC,0x01,	// 150
	0xFC,0x01,0x04,0x01,0x04,0x01,0xFC,0x01,	// 151
	0xFC,0x01,0x04,0x01,0x04,0x01,0xFC,0x01,	// 152
	0xFC,0x01,0x04,0x01,0x04,0x01,0xFC,0x01,	// 153
	0xFC,0x01,0x04,0x01,0x04,0x01,0xFC,0x01,	// 154
	0xFC,0x01,0x04,0x01,0x04,0x01,0xFC,0x01,	// 155
	0xFC,0x01,0x04,0x01,0x04,0x01,0xFC,0x01,	// 156
	0xFC,0x01,0x04,0x01,0x04,0x01,0xFC,0x01,	// 157
	0xFC,0x01,0x04,0x01,0x04,0x01,0xFC,0x01,	// 158
	0xFC,0x01,0x04,0x01,0x04,0x01,0xFC,0x01,	// 159
	0x00,0x00,0xD0,0x03,	// 161
	0x00,0x00,0xF0,0x00,0xF8,0x01,0x90,	// 162
	0xA0,0x00,0xFC,0x00,0xA4,0x00,0xA4,	// 163
	0x88,0x00,0x70,0x00,0x50,0x00,0x70,0x00,0x88,	// 164
	0x54,0x00,0x58,0x00,0xE0,0x00,0x58,0x00,0x54,	// 165
	0x00,0x00,0xDC,0x01,	// 166
	0x00,0x00,0x3C,0x01,0x54,0x01,0xE4,0x01,	// 167
	0x00,0x00,0x04,0x00,0x00,0x00,0x04,	// 168
	0x00,0x00,0x78,0x00,0xCC,0x00,0xB4,0x00,0xB4,0x00,0xCC,0x00,0x78,	// 169
	0x00,0x00,0x58,0x00,0x5C,0x00,0x5C,	// 170
	0x00,0x00,0x60,0x00,0xF0,0x00,0x60,0x00,0xF0,	// 171
	0x00,0x00,0x20,0x00,0x20,0x00,0x20,0x00,0x20,0x00,0x60,	// 172
	0x00,0x00,0x20,0x00,0x20,	// 173
	0x00,0x00,0x78,0x00,0xCC,0x00,0xB4,0x00,0xB4,0x00,0xCC,0x00,0x78,	// 174
	0x00,0x00,0x04,0x00,0x04,	// 175
	0x00,0x00,0x0C,0x00,0x0C,	// 176
	0x00,0x00,0x90,0x00,0x90,0x00,0xFC,0x00,0x90,0x00,0x90,	// 177
	0x00,0x00,0x14,0x00,0x1C,	// 178
	0x00,0x00,0x1C,0x00,0x14,	// 179
	0x00,0x00,0x04,	// 180
	0x00,0x00,0xF0,0x03,0x80,0x00,0x80,0x00,0xF0,	// 181
	0x00,0x00,0x3C,0x00,0xFC,0x01,0x04,0x00,0xFC,0x01,	// 182
	0x00,0x00,0x20,	// 183
	0x00,0x00,0x00,0x02,0x00,0x03,	// 184
	0x00,0x00,0x14,0x00,0x1C,	// 185
	0x00,0x00,0x5C,0x00,0x54,0x00,0x5C,	// 186
	0x00,0x00,0xF0,0x00,0x60,0x00,0xF0,0x00,0x60,	// 187
	0x00,0x00,0x14,0x00,0x9C,0x00,0x70,0x00,0x18,0x00,0x04,0x00,0xC0,0x00,0xE0,	// 188
	0x00,0x00,0x14,0x00,0x9C,0x00,0x70,0x00,0x18,0x00,0x04,0x00,0xA0,0x00,0xE0,	// 189
	0x00,0x00,0x1C,0x00,0x94,0x00,0x60,0x00,0x18,0x00,0x04,0x00,0xC0,0x00,0xE0,	// 190
	0x00,0x00,0x00,0x03,0xD0,0x02,0x00,0x02,	// 191
	0x80,0x00,0x70,0x00,0x4E,0x00,0x72,0x00,0x80,	// 192
	0x80,0x00,0x70,0x00,0x4E,0x00,0x72,0x00,0x80,	// 193
	0x80,0x00,0x70,0x00,0x4C,0x00,0x70,0x00,0x80,	// 194
	0x80,0x00,0x72,0x00,0x4E,0x00,0x72,0x00,0x80,	// 195
	0x80,0x00,0x72,0x00,0x4C,0x00,0x72,0x00,0x80,	// 196
	0x80,0x00,0x60,0x00,0x5F,0x00,0x60,0x00,0x80,	// 197
	0x80,0x00,0x70,0x00,0x4C,0x00,0xFC,0x00,0xA4,0x00,0xA4,0x00,0xA4,	// 198
	0x00,0x00,0x78,0x00,0xCC,0x02,0x84,0x03,0x84,0x00,0x88,	// 199
	0x00,0x00,0xFC,0x00,0xA6,0x00,0xA6,0x00,0xA4,	// 200
	0x00,0x00,0xFC,0x00,0xA6,0x00,0xA6,0x00,0xA4,	// 201
	0x00,0x00,0xFC,0x00,0xA6,0x00,0xA6,0x00,0xA4,	// 202
	0x00,0x00,0xFC,0x00,0xA6,0x00,0xA4,0x00,0xA6,	// 203
	0x02,0x00,0xFE,	// 204
	0x02,0x00,0xFE,	// 205
	0x02,0x00,0xFE,	// 206
	0x02,0x00,0xFC,	// 207
	0x20,0x00,0xFC,0x00,0xA4,0x00,0x84,0x00,0xCC,0x00,0x78,	// 208
	0x00,0x00,0xFC,0x00,0x1A,0x00,0x62,0x00,0xFC,	// 209
	0x00,0x00,0x78,0x00,0x86,0x00,0x86,0x00,0x84,0x00,0x78,	// 210
	0x00,0x00,0x78,0x00,0x86,0x00,0x86,0x00,0x84,0x00,0x78,	// 211
	0x00,0x00,0x78,0x00,0x84,0x00,0x84,0x00,0x84,0x00,0x78,	// 212
	0x00,0x00,0x78,0x00,0x86,0x00,0x86,0x00,0x86,0x00,0x78,	// 213
	0x00,0x00,0x78,0x00,0x86,0x00,0x84,0x00,0x86,0x00,0x78,	// 214
	0x00,0x00,0x88,0x00,0x50,0x00,0x20,0x00,0x50,0x00,0x88,	// 215
	0x00,0x00,0xB8,0x00,0xE4,0x00,0x94,0x00,0x8C,0x00,0x74,	// 216
	0x00,0x00,0x7C,0x00,0x82,0x00,0x82,0x00,0x7C,	// 217
	0x00,0x00,0x7C,0x00,0x82,0x00,0x82,0x00,0x7C,	// 218
	0x00,0x00,0x7C,0x00,0x82,0x00,0x82,0x00,0x7C,	// 219
	0x00,0x00,0x7E,0x00,0x80,0x00,0x80,0x00,0x7E,	// 220
	0x04,0x00,0x0E,0x00,0xF2,0x00,0x0C,0x00,0x04,	// 221
	0x00,0x00,0xFC,0x00,0x28,0x00,0x28,0x00,0x38,	// 222
	0x00,0x00,0xFC,0x00,0x02,0x00,0x9A,0x00,0xE4,	// 223
	0x00,0x00,0xE4,0x00,0xB0,0x00,0xB0,0x00,0xF0,	// 224
	0x00,0x00,0xE4,0x00,0xB0,0x00,0xB0,0x00,0xF0,	// 225
	0x00,0x00,0xE0,0x00,0xB4,0x00,0xB4,0x00,0xF0,	// 226
	0x00,0x00,0xE0,0x00,0xBC,0x00,0xBC,0x00,0xF0,	// 227
	0x00,0x00,0xE0,0x00,0xB4,0x00,0xB4,0x00,0xF0,	// 228
	0x00,0x00,0xE0,0x00,0xB6,0x00,0xB6,0x00,0xF0,	// 229
	0x00,0x00,0xE0,0x00,0xB0,0x00,0xB0,0x00,0x60,0x00,0xB0,0x00,0xB0,0x00,0xB0,	// 230
	0x00,0x00,0x60,0x00,0x90,0x02,0x90,0x03,	// 231
	0x00,0x00,0x60,0x00,0xB4,0x00,0xB0,0x00,0xB0,	// 232
	0x00,0x00,0x60,0x00,0xB4,0x00,0xB0,0x00,0xB0,	// 233
	0x00,0x00,0x60,0x00,0xB4,0x00,0xB4,0x00,0xB0,	// 234
	0x00,0x00,0x60,0x00,0xB4,0x00,0xB0,0x00,0xB4,	// 235
	0x04,0x00,0xF0,	// 236
	0x04,0x00,0xF0,	// 237
	0x04,0x00,0xF4,	// 238
	0x04,0x00,0xF0,	// 239
	0x00,0x00,0x60,0x00,0x94,0x00,0x9C,0x00,0x70,	// 240
	0x00,0x00,0xFC,0x00,0x1C,0x00,0x1C,0x00,0xF0,	// 241
	0x00,0x00,0x64,0x00,0x90,0x00,0x90,0x00,0x60,	// 242
	0x00,0x00,0x64,0x00,0x90,0x00,0x90,0x00,0x60,	// 243
	0x00,0x00,0x60,0x00,0x94,0x00,0x94,0x00,0x60,	// 244
	0x00,0x00,0x60,0x00,0x9C,0x00,0x9C,0x00,0x60,	// 245
	0x00,0x00,0x64,0x00,0x90,0x00,0x90,0x00,0x64,	// 246
	0x00,0x00,0x20,0x00,0x20,0x00,0xA8,0x00,0x20,0x00,0x20,	// 247
	0x00,0x00,0xF0,0x00,0xD0,0x00,0xB0,0x00,0xF0,	// 248
	0x00,0x00,0xF4,0x00,0x80,0x00,0x80,0x00,0xF0,	// 249
	0x00,0x00,0xF4,0x00,0x80,0x00,0x80,0x00,0xF0,	// 250
	0x00,0x00,0xF0,0x00,0x84,0x00,0x84,0x00,0xF0,	// 251
	0x00,0x00,0xF0,0x00,0x84,0x00,0x84,0x00,0xF0,	// 252
	0x00,0x00,0x14,0x02,0xE0,0x03,0x60,0x00,0x10,	// 253
	0x00,0x00,0xFE,0x03,0x90,0x00,0x90,0x00,0x60,	// 254
	0x00,0x00,0x14,0x02,0xE0,0x03,0x64,0x00,0x10	// 255
};

================================================
FILE: examples/SSD1306FontTryout/SSD1306FontTryout.ino
================================================
/**
   The MIT License (MIT)

   Permission is hereby granted, free of charge, to any person obtaining a copy
   of this software and associated documentation files (the "Software"), to deal
   in the Software without restriction, including without limitation the rights
   to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
   copies of the Software, and to permit persons to whom the Software is
   furnished to do so, subject to the following conditions:

   The above copyright notice and this permission notice shall be included in all
   copies or substantial portions of the Software.

   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
   AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
   OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
   SOFTWARE.

   ThingPulse invests considerable time and money to develop these open source libraries.
   Please support us by buying our products (and not the clones) from
   https://thingpulse.com

*/

/**
   Using this sketch, you can try out the fonts. Simply generate new font files
   at https://oleddisplay.squix.ch/ , download them and add to your sketch with
   "Sketch / Add file" in the Arduino IDE. Then include them and add their names
   to loop(). You'll see the name of the font on the serial monitor as the
   sketch cycles through them.
*/

// Include the correct display library
// For a connection via I2C using Wire include
#include <Wire.h>  // Only needed for Arduino 1.6.5 and earlier
#include "SSD1306Wire.h" // legacy include: `#include "SSD1306.h"`
// or #include "SH1106Wire.h", legacy include: `#include "SH1106.h"`
// For a connection via I2C using brzo_i2c (must be installed) include
// #include <brzo_i2c.h> // Only needed for Arduino 1.6.5 and earlier
// #include "SSD1306Brzo.h"
// #include "SH1106Brzo.h"
// For a connection via SPI include
// #include <SPI.h> // Only needed for Arduino 1.6.5 and earlier
// #include "SSD1306Spi.h"
// #include "SH1106SPi.h"

// Use the corresponding display class:

// Initialize the OLED display using SPI
// D5 -> CLK
// D7 -> MOSI (DOUT)
// D0 -> RES
// D2 -> DC
// D8 -> CS
// SSD1306Spi        display(D0, D2, D8);
// or
// SH1106Spi         display(D0, D2);

// Initialize the OLED display using brzo_i2c
// D3 -> SDA
// D5 -> SCL
// SSD1306Brzo display(0x3c, D3, D5);
// or
// SH1106Brzo  display(0x3c, D3, D5);

// Initialize the OLED display using Wire library
SSD1306Wire display(0x3c, SDA, SCL);   // ADDRESS, SDA, SCL  -  SDA and SCL usually populate automatically based on your board's pins_arduino.h e.g. https://github.com/esp8266/Arduino/blob/master/variants/nodemcu/pins_arduino.h
// SH1106Wire display(0x3c, SDA, SCL);

// Include all the font files you add to the Sketch
#include "Dialog_plain_8.h"
#include "Dialog_plain_7.h"
#include "Dialog_plain_6.h"


// This will call the function doPrint() with the name;
// once without and once with quotes.
#define DO_PRINT(a) doPrint(a, #a); 


void setup() {
  display.init();

  // display.flipScreenVertically();

  display.setContrast(255);
}

void loop() {
  
  // These three fonts come with the display driver
  DO_PRINT(ArialMT_Plain_10);
  DO_PRINT(ArialMT_Plain_16);
  DO_PRINT(ArialMT_Plain_24);

  // These three I had generated and added as files
  DO_PRINT(Dialog_plain_6);
  DO_PRINT(Dialog_plain_7);
  DO_PRINT(Dialog_plain_8);

}


void doPrint(const uint8_t* font, String fontname) {
  Serial.println(fontname);

  display.cls();
  display.setFont(font);

  display.println("Lorem ipsum dolor sit amet, consectetur");
  display.println("adipiscing elit, sed do eiusmod tempor");
  display.println("incididunt ut labore et dolore magna aliqua.");
  display.println("Ut enim ad minim veniam, quis nostrud exercitation");
  display.println("ullamco laboris nisi ut aliquip ex ea commodo");
  display.println("consequat. Duis aute irure dolor in reprehenderit");
  display.println("in voluptate velit esse cillum dolore eu fugiat");
  display.println("nulla pariatur. Excepteur sint occaecat cupidatat");
  display.println("non proident, sunt in culpa qui officia deserunt.");

  delay(5000);

}

// The library comes with fonts as a const uint8_t array, the site at
// https://oleddisplay.squix.ch/ generates them as const char array. This code
// converts one in the other to make sure both work here.
void doPrint(const char* font, String fontname) {
  doPrint(static_cast<const uint8_t*>(reinterpret_cast<const void*>(font)), fontname);
}


================================================
FILE: examples/SSD1306OTADemo/SSD1306OTADemo.ino
================================================
/**
   The MIT License (MIT)

   Copyright (c) 2018 by ThingPulse, Daniel Eichhorn
   Copyright (c) 2018 by Fabrice Weinberg

   Permission is hereby granted, free of charge, to any person obtaining a copy
   of this software and associated documentation files (the "Software"), to deal
   in the Software without restriction, including without limitation the rights
   to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
   copies of the Software, and to permit persons to whom the Software is
   furnished to do so, subject to the following conditions:

   The above copyright notice and this permission notice shall be included in all
   copies or substantial portions of the Software.

   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
   AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
   OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
   SOFTWARE.

   ThingPulse invests considerable time and money to develop these open source libraries.
   Please support us by buying our products (and not the clones) from
   https://thingpulse.com

*/

#if defined(ESP8266)
#include <ESP8266WiFi.h>
#include <ESP8266mDNS.h>
#elif defined(ESP32)
#include <WiFi.h>
#include <ESPmDNS.h>
#include <WiFiUdp.h>
#endif

#include <ArduinoOTA.h>

const char *ssid         = "[Your SSID]";
const char *password     = "[Your Password]";


// Include the correct display library
// For a connection via I2C using Wire include
#include <Wire.h>  // Only needed for Arduino 1.6.5 and earlier
#include "SSD1306Wire.h" // legacy include: `#include "SSD1306.h"`
// or #include "SH1106Wire.h", legacy include: `#include "SH1106.h"`
// For a connection via I2C using brzo_i2c (must be installed) include
// #include <brzo_i2c.h> // Only needed for Arduino 1.6.5 and earlier
// #include "SSD1306Brzo.h"
// #include "SH1106Brzo.h"
// For a connection via SPI include
// #include <SPI.h> // Only needed for Arduino 1.6.5 and earlier
// #include "SSD1306Spi.h"
// #include "SH1106SPi.h"

// Use the corresponding display class:

// Initialize the OLED display using SPI
// D5 -> CLK
// D7 -> MOSI (DOUT)
// D0 -> RES
// D2 -> DC
// D8 -> CS
// SSD1306Spi        display(D0, D2, D8);
// or
// SH1106Spi         display(D0, D2);

// Initialize the OLED display using brzo_i2c
// D3 -> SDA
// D5 -> SCL
// SSD1306Brzo display(0x3c, D3, D5);
// or
// SH1106Brzo  display(0x3c, D3, D5);

// Initialize the OLED display using Wire library
SSD1306Wire display(0x3c, SDA, SCL);   // ADDRESS, SDA, SCL  -  SDA and SCL usually populate automatically based on your board's pins_arduino.h e.g. https://github.com/esp8266/Arduino/blob/master/variants/nodemcu/pins_arduino.h
// SH1106Wire display(0x3c, SDA, SCL);


void setup() {
  WiFi.begin ( ssid, password );

  // Wait for connection
  while ( WiFi.status() != WL_CONNECTED ) {
    delay ( 10 );
  }

  display.init();
  display.flipScreenVertically();
  display.setContrast(255);

  ArduinoOTA.begin();
  ArduinoOTA.onStart([]() {
    display.clear();
    display.setFont(ArialMT_Plain_10);
    display.setTextAlignment(TEXT_ALIGN_CENTER_BOTH);
    display.drawString(display.getWidth() / 2, display.getHeight() / 2 - 10, "OTA Update");
    display.display();
  });

  ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) {
    display.drawProgressBar(4, 32, 120, 8, progress / (total / 100) );
    display.display();
  });

  ArduinoOTA.onEnd([]() {
    display.clear();
    display.setFont(ArialMT_Plain_10);
    display.setTextAlignment(TEXT_ALIGN_CENTER_BOTH);
    display.drawString(display.getWidth() / 2, display.getHeight() / 2, "Restart");
    display.display();
  });

  // Align text vertical/horizontal center
  display.setTextAlignment(TEXT_ALIGN_CENTER_BOTH);
  display.setFont(ArialMT_Plain_10);
  display.drawString(display.getWidth() / 2, display.getHeight() / 2, "Ready for OTA:\n" + WiFi.localIP().toString());
  display.display();
}

void loop() {
  ArduinoOTA.handle();
}


================================================
FILE: examples/SSD1306ScrollVerticalDemo/SSD1306ScrollVerticalDemo.ino
================================================
/**
   The MIT License (MIT)

   Copyright (c) 2022 by Stefan Seyfried

   Permission is hereby granted, free of charge, to any person obtaining a copy
   of this software and associated documentation files (the "Software"), to deal
   in the Software without restriction, including without limitation the rights
   to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
   copies of the Software, and to permit persons to whom the Software is
   furnished to do so, subject to the following conditions:

   The above copyright notice and this permission notice shall be included in all
   copies or substantial portions of the Software.

   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
   AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
   OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
   SOFTWARE.
*/

// Include the correct display library
// For a connection via I2C using Wire include
#include <Wire.h>  // Only needed for Arduino 1.6.5 and earlier
#include "SSD1306Wire.h" // legacy include: `#include "SSD1306.h"`
// or #include "SH1106Wire.h", legacy include: `#include "SH1106.h"`
// For a connection via I2C using brzo_i2c (must be installed) include
// #include <brzo_i2c.h> // Only needed for Arduino 1.6.5 and earlier
// #include "SSD1306Brzo.h"
// #include "SH1106Brzo.h"
// For a connection via SPI include
// #include <SPI.h> // Only needed for Arduino 1.6.5 and earlier
// #include "SSD1306Spi.h"
// #include "SH1106Spi.h"

// Use the corresponding display class:

// Initialize the OLED display using SPI
// D5 -> CLK
// D7 -> MOSI (DOUT)
// D0 -> RES
// D2 -> DC
// D8 -> CS
// SSD1306Spi        display(D0, D2, D8);
// or
// SH1106Spi         display(D0, D2);

// Initialize the OLED display using brzo_i2c
// D3 -> SDA
// D5 -> SCL
// SSD1306Brzo display(0x3c, D3, D5);
// or
// SH1106Brzo  display(0x3c, D3, D5);

// Initialize the OLED display using Wire library
SSD1306Wire display(0x3c, SDA, SCL);   // ADDRESS, SDA, SCL  -  SDA and SCL usually populate automatically based on your board's pins_arduino.h e.g. https://github.com/esp8266/Arduino/blob/master/variants/nodemcu/pins_arduino.h
// SH1106Wire display(0x3c, SDA, SCL);

// UTF-8 sprinkled within, because it tests special conditions in the char-counting code
const String loremipsum = "Lorem ipsum dolor sit ämet, "
  "consetetur sadipscing elitr, sed diam nonümy eirmöd "
  "tempor invidunt ut labore et dolore mägnä aliquyam erat, "
  "sed diam voluptua. At vero eos et accusam et justo duo "
  "dolores et ea rebum. Stet clita kasd gubergren, no sea "
  "takimata sanctus est Lorem ipsum dolor sit amet. "
  "äöü-ÄÖÜ/߀é/çØ.";

void setup() {
  display.init();
  display.setContrast(255);
  display.setTextAlignment(TEXT_ALIGN_LEFT);
  display.setFont(ArialMT_Plain_16);
  display.display();
}

void loop() {
  static uint16_t start_at = 0;
  display.clear();
  uint16_t firstline = display.drawStringMaxWidth(0, 0, 128, loremipsum.substring(start_at));
  display.display();
  if (firstline != 0) {
    start_at += firstline;
  } else {
    start_at = 0;
    delay(1000); // additional pause before going back to start
  }
  delay(1000);
}


================================================
FILE: examples/SSD1306SimpleDemo/SSD1306SimpleDemo.ino
================================================
/**
   The MIT License (MIT)

   Copyright (c) 2018 by ThingPulse, Daniel Eichhorn
   Copyright (c) 2018 by Fabrice Weinberg

   Permission is hereby granted, free of charge, to any person obtaining a copy
   of this software and associated documentation files (the "Software"), to deal
   in the Software without restriction, including without limitation the rights
   to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
   copies of the Software, and to permit persons to whom the Software is
   furnished to do so, subject to the following conditions:

   The above copyright notice and this permission notice shall be included in all
   copies or substantial portions of the Software.

   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
   AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
   OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
   SOFTWARE.

   ThingPulse invests considerable time and money to develop these open source libraries.
   Please support us by buying our products (and not the clones) from
   https://thingpulse.com

*/

// Include the correct display library

// For a connection via I2C using the Arduino Wire include:
#include <Wire.h>               // Only needed for Arduino 1.6.5 and earlier
#include "SSD1306Wire.h"        // legacy: #include "SSD1306.h"
// OR #include "SH1106Wire.h"   // legacy: #include "SH1106.h"

// For a connection via I2C using brzo_i2c (must be installed) include:
// #include <brzo_i2c.h>        // Only needed for Arduino 1.6.5 and earlier
// #include "SSD1306Brzo.h"
// OR #include "SH1106Brzo.h"

// For a connection via SPI include:
// #include <SPI.h>             // Only needed for Arduino 1.6.5 and earlier
// #include "SSD1306Spi.h"
// OR #include "SH1106SPi.h"


// Optionally include custom images
#include "images.h"


// Initialize the OLED display using Arduino Wire:
SSD1306Wire display(0x3c, SDA, SCL);   // ADDRESS, SDA, SCL  -  SDA and SCL usually populate automatically based on your board's pins_arduino.h e.g. https://github.com/esp8266/Arduino/blob/master/variants/nodemcu/pins_arduino.h
// SSD1306Wire display(0x3c, D3, D5);  // ADDRESS, SDA, SCL  -  If not, they can be specified manually.
// SSD1306Wire display(0x3c, SDA, SCL, GEOMETRY_128_32);  // ADDRESS, SDA, SCL, OLEDDISPLAY_GEOMETRY  -  Extra param required for 128x32 displays.
// SH1106Wire display(0x3c, SDA, SCL);     // ADDRESS, SDA, SCL

// Initialize the OLED display using brzo_i2c:
// SSD1306Brzo display(0x3c, D3, D5);  // ADDRESS, SDA, SCL
// or
// SH1106Brzo display(0x3c, D3, D5);   // ADDRESS, SDA, SCL

// Initialize the OLED display using SPI:
// D5 -> CLK
// D7 -> MOSI (DOUT)
// D0 -> RES
// D2 -> DC
// D8 -> CS
// SSD1306Spi display(D0, D2, D8);  // RES, DC, CS
// or
// SH1106Spi display(D0, D2);       // RES, DC


#define DEMO_DURATION 3000
typedef void (*Demo)(void);

int demoMode = 0;
int counter = 1;

void setup() {
  Serial.begin(115200);
  Serial.println();
  Serial.println();


  // Initialising the UI will init the display too.
  display.init();

  display.flipScreenVertically();
  display.setFont(ArialMT_Plain_10);

}

void drawFontFaceDemo() {
  // Font Demo1
  // create more fonts at http://oleddisplay.squix.ch/
  display.setTextAlignment(TEXT_ALIGN_LEFT);
  display.setFont(ArialMT_Plain_10);
  display.drawString(0, 0, "Hello world");
  display.setFont(ArialMT_Plain_16);
  display.drawString(0, 10, "Hello world");
  display.setFont(ArialMT_Plain_24);
  display.drawString(0, 26, "Hello world");
}

void drawTextFlowDemo() {
  display.setFont(ArialMT_Plain_10);
  display.setTextAlignment(TEXT_ALIGN_LEFT);
  display.drawStringMaxWidth(0, 0, 128,
                             "Lorem ipsum\n dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore." );
}

void drawTextAlignmentDemo() {
  // Text alignment demo
  display.setFont(ArialMT_Plain_10);

  // The coordinates define the left starting point of the text
  display.setTextAlignment(TEXT_ALIGN_LEFT);
  display.drawString(0, 10, "Left aligned (0,10)");

  // The coordinates define the center of the text
  display.setTextAlignment(TEXT_ALIGN_CENTER);
  display.drawString(64, 22, "Center aligned (64,22)");

  // The coordinates define the right end of the text
  display.setTextAlignment(TEXT_ALIGN_RIGHT);
  display.drawString(128, 33, "Right aligned (128,33)");
}

void drawRectDemo() {
  // Draw a pixel at given position
  for (int i = 0; i < 10; i++) {
    display.setPixel(i, i);
    display.setPixel(10 - i, i);
  }
  display.drawRect(12, 12, 20, 20);

  // Fill the rectangle
  display.fillRect(14, 14, 17, 17);

  // Draw a line horizontally
  display.drawHorizontalLine(0, 40, 20);

  // Draw a line horizontally
  display.drawVerticalLine(40, 0, 20);
}

void drawCircleDemo() {
  for (int i = 1; i < 8; i++) {
    display.setColor(WHITE);
    display.drawCircle(32, 32, i * 3);
    if (i % 2 == 0) {
      display.setColor(BLACK);
    }
    display.fillCircle(96, 32, 32 - i * 3);
  }
}

void drawProgressBarDemo() {
  int progress = (counter / 5) % 100;
  // draw the progress bar
  display.drawProgressBar(0, 32, 120, 10, progress);

  // draw the percentage as String
  display.setTextAlignment(TEXT_ALIGN_CENTER);
  display.drawString(64, 15, String(progress) + "%");
}

void drawImageDemo() {
  // see http://blog.squix.org/2015/05/esp8266-nodemcu-how-to-create-xbm.html
  // on how to create xbm files
  display.drawXbm(34, 14, WiFi_Logo_width, WiFi_Logo_height, WiFi_Logo_bits);
}

Demo demos[] = {drawFontFaceDemo, drawTextFlowDemo, drawTextAlignmentDemo, drawRectDemo, drawCircleDemo, drawProgressBarDemo, drawImageDemo};
int demoLength = (sizeof(demos) / sizeof(Demo));
long timeSinceLastModeSwitch = 0;

void loop() {
  // clear the display
  display.clear();
  // draw the current demo method
  demos[demoMode]();

  display.setFont(ArialMT_Plain_10);
  display.setTextAlignment(TEXT_ALIGN_RIGHT);
  display.drawString(128, 54, String(millis()));
  // write the buffer to the display
  display.display();

  if (millis() - timeSinceLastModeSwitch > DEMO_DURATION) {
    demoMode = (demoMode + 1)  % demoLength;
    timeSinceLastModeSwitch = millis();
  }
  counter++;
  delay(10);
}


================================================
FILE: examples/SSD1306SimpleDemo/images.h
================================================
#define WiFi_Logo_width 60
#define WiFi_Logo_height 36
const uint8_t WiFi_Logo_bits[] PROGMEM = {
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0x07, 0x00, 0x00, 0x00,
  0x00, 0x00, 0xE0, 0xFF, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF,
  0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0xFF, 0xFF, 0x00, 0x00, 0x00,
  0x00, 0x00, 0xFE, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF,
  0xFF, 0x03, 0x00, 0x00, 0x00, 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00,
  0x00, 0xFF, 0xFF, 0xFF, 0x07, 0xC0, 0x83, 0x01, 0x80, 0xFF, 0xFF, 0xFF,
  0x01, 0x00, 0x07, 0x00, 0xC0, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x0C, 0x00,
  0xC0, 0xFF, 0xFF, 0x7C, 0x00, 0x60, 0x0C, 0x00, 0xC0, 0x31, 0x46, 0x7C,
  0xFC, 0x77, 0x08, 0x00, 0xE0, 0x23, 0xC6, 0x3C, 0xFC, 0x67, 0x18, 0x00,
  0xE0, 0x23, 0xE4, 0x3F, 0x1C, 0x00, 0x18, 0x00, 0xE0, 0x23, 0x60, 0x3C,
  0x1C, 0x70, 0x18, 0x00, 0xE0, 0x03, 0x60, 0x3C, 0x1C, 0x70, 0x18, 0x00,
  0xE0, 0x07, 0x60, 0x3C, 0xFC, 0x73, 0x18, 0x00, 0xE0, 0x87, 0x70, 0x3C,
  0xFC, 0x73, 0x18, 0x00, 0xE0, 0x87, 0x70, 0x3C, 0x1C, 0x70, 0x18, 0x00,
  0xE0, 0x87, 0x70, 0x3C, 0x1C, 0x70, 0x18, 0x00, 0xE0, 0x8F, 0x71, 0x3C,
  0x1C, 0x70, 0x18, 0x00, 0xC0, 0xFF, 0xFF, 0x3F, 0x00, 0x00, 0x08, 0x00,
  0xC0, 0xFF, 0xFF, 0x1F, 0x00, 0x00, 0x0C, 0x00, 0x80, 0xFF, 0xFF, 0x1F,
  0x00, 0x00, 0x06, 0x00, 0x80, 0xFF, 0xFF, 0x0F, 0x00, 0x00, 0x07, 0x00,
  0x00, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0xF8, 0xFF, 0xFF,
  0xFF, 0x7F, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0xFF, 0x01, 0x00, 0x00,
  0x00, 0x00, 0xFC, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF,
  0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xFF, 0x1F, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x80, 0xFF, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  };


================================================
FILE: examples/SSD1306TwoScreenDemo/SSD1306TwoScreenDemo.ino
================================================
/**
   The MIT License (MIT)

   Copyright (c) 2018 by ThingPulse, Daniel Eichhorn

   Permission is hereby granted, free of charge, to any person obtaining a copy
   of this software and associated documentation files (the "Software"), to deal
   in the Software without restriction, including without limitation the rights
   to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
   copies of the Software, and to permit persons to whom the Software is
   furnished to do so, subject to the following conditions:

   The above copyright notice and this permission notice shall be included in all
   copies or substantial portions of the Software.

   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
   AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
   OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
   SOFTWARE.

   ThingPulse invests considerable time and money to develop these open source libraries.
   Please support us by buying our products (and not the clones) from
   https://thingpulse.com

*/

// Include the correct display library
// For a connection via I2C using Wire include
#include <Wire.h>  // Only needed for Arduino 1.6.5 and earlier
#include "SSD1306Wire.h" // legacy include: `#include "SSD1306.h"`
#include "images.h"

// Initialize the OLED display using Wire library
//
// GOTCHA!
//
// Pay attention if you work with ESP32 as some have two I2C buses.
// You need to set the 'i2cBus' constructor parameter accordingly.
// See https://github.com/ThingPulse/esp8266-oled-ssd1306/issues/387#issuecomment-2874437238 for a discussion.
SSD1306Wire  display(0x3c, 0, 14);
SSD1306Wire  display2(0x3c, 5, 4);

void setup() {
  Serial.begin(115200);
  Serial.println();
  Serial.println();


  // Initialising the UI will init the display too.
  display.init();
  display2.init();

  // This will make sure that multiple instances of a display driver
  // running on different ports will work together transparently
  display.setI2cAutoInit(true);
  display2.setI2cAutoInit(true);

  display.flipScreenVertically();
  display.setFont(ArialMT_Plain_10);
  display.setTextAlignment(TEXT_ALIGN_LEFT);

  display2.flipScreenVertically();
  display2.setFont(ArialMT_Plain_10);
  display2.setTextAlignment(TEXT_ALIGN_LEFT);

}

void loop() {
  display.clear();
  display.drawString(0, 0, "Hello world: " + String(millis()));
  display.display();

  display2.clear();
  display2.drawString(0, 0, "Hello world: " + String(millis()));
  display2.display();

  delay(10);
}


================================================
FILE: examples/SSD1306TwoScreenDemo/images.h
================================================
#define WiFi_Logo_width 60
#define WiFi_Logo_height 36
const uint8_t WiFi_Logo_bits[] PROGMEM = {
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0x07, 0x00, 0x00, 0x00,
  0x00, 0x00, 0xE0, 0xFF, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF,
  0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0xFF, 0xFF, 0x00, 0x00, 0x00,
  0x00, 0x00, 0xFE, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF,
  0xFF, 0x03, 0x00, 0x00, 0x00, 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00,
  0x00, 0xFF, 0xFF, 0xFF, 0x07, 0xC0, 0x83, 0x01, 0x80, 0xFF, 0xFF, 0xFF,
  0x01, 0x00, 0x07, 0x00, 0xC0, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x0C, 0x00,
  0xC0, 0xFF, 0xFF, 0x7C, 0x00, 0x60, 0x0C, 0x00, 0xC0, 0x31, 0x46, 0x7C,
  0xFC, 0x77, 0x08, 0x00, 0xE0, 0x23, 0xC6, 0x3C, 0xFC, 0x67, 0x18, 0x00,
  0xE0, 0x23, 0xE4, 0x3F, 0x1C, 0x00, 0x18, 0x00, 0xE0, 0x23, 0x60, 0x3C,
  0x1C, 0x70, 0x18, 0x00, 0xE0, 0x03, 0x60, 0x3C, 0x1C, 0x70, 0x18, 0x00,
  0xE0, 0x07, 0x60, 0x3C, 0xFC, 0x73, 0x18, 0x00, 0xE0, 0x87, 0x70, 0x3C,
  0xFC, 0x73, 0x18, 0x00, 0xE0, 0x87, 0x70, 0x3C, 0x1C, 0x70, 0x18, 0x00,
  0xE0, 0x87, 0x70, 0x3C, 0x1C, 0x70, 0x18, 0x00, 0xE0, 0x8F, 0x71, 0x3C,
  0x1C, 0x70, 0x18, 0x00, 0xC0, 0xFF, 0xFF, 0x3F, 0x00, 0x00, 0x08, 0x00,
  0xC0, 0xFF, 0xFF, 0x1F, 0x00, 0x00, 0x0C, 0x00, 0x80, 0xFF, 0xFF, 0x1F,
  0x00, 0x00, 0x06, 0x00, 0x80, 0xFF, 0xFF, 0x0F, 0x00, 0x00, 0x07, 0x00,
  0x00, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0xF8, 0xFF, 0xFF,
  0xFF, 0x7F, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0xFF, 0x01, 0x00, 0x00,
  0x00, 0x00, 0xFC, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF,
  0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xFF, 0x1F, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x80, 0xFF, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  };


================================================
FILE: examples/SSD1306UiDemo/SSD1306UiDemo.ino
================================================
/**
   The MIT License (MIT)

   Copyright (c) 2018 by ThingPulse, Daniel Eichhorn
   Copyright (c) 2018 by Fabrice Weinberg

   Permission is hereby granted, free of charge, to any person obtaining a copy
   of this software and associated documentation files (the "Software"), to deal
   in the Software without restriction, including without limitation the rights
   to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
   copies of the Software, and to permit persons to whom the Software is
   furnished to do so, subject to the following conditions:

   The above copyright notice and this permission notice shall be included in all
   copies or substantial portions of the Software.

   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
   AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
   OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
   SOFTWARE.

   ThingPulse invests considerable time and money to develop these open source libraries.
   Please support us by buying our products (and not the clones) from
   https://thingpulse.com

*/

// Include the correct display library
// For a connection via I2C using Wire include
#include <Wire.h>  // Only needed for Arduino 1.6.5 and earlier
#include "SSD1306Wire.h" // legacy include: `#include "SSD1306.h"`
// or #include "SH1106Wire.h", legacy include: `#include "SH1106.h"`
// For a connection via I2C using brzo_i2c (must be installed) include
// #include <brzo_i2c.h> // Only needed for Arduino 1.6.5 and earlier
// #include "SSD1306Brzo.h"
// #include "SH1106Brzo.h"
// For a connection via SPI include
// #include <SPI.h> // Only needed for Arduino 1.6.5 and earlier
// #include "SSD1306Spi.h"
// #include "SH1106SPi.h"

// Include the UI lib
#include "OLEDDisplayUi.h"

// Include custom images

#include "images.h"

// Use the corresponding display class:

// Initialize the OLED display using SPI
// D5 -> CLK
// D7 -> MOSI (DOUT)
// D0 -> RES
// D2 -> DC
// D8 -> CS
// SSD1306Spi        display(D0, D2, D8);
// or
// SH1106Spi         display(D0, D2);

// Initialize the OLED display using brzo_i2c
// D3 -> SDA
// D5 -> SCL
// SSD1306Brzo display(0x3c, D3, D5);
// or
// SH1106Brzo  display(0x3c, D3, D5);

// Initialize the OLED display using Wire library
SSD1306Wire display(0x3c, SDA, SCL);  // ADDRESS, SDA, SCL  -  SDA and SCL usually populate automatically based on your board's pins_arduino.h e.g. https://github.com/esp8266/Arduino/blob/master/variants/nodemcu/pins_arduino.h
// SH1106Wire display(0x3c, SDA, SCL);

OLEDDisplayUi ui     ( &display );

void msOverlay(OLEDDisplay *display, OLEDDisplayUiState* state) {
  display->setTextAlignment(TEXT_ALIGN_RIGHT);
  display->setFont(ArialMT_Plain_10);
  display->drawString(128, 0, String(millis()));
}

void drawFrame1(OLEDDisplay *display, OLEDDisplayUiState* state, int16_t x, int16_t y) {
  // draw an xbm image.
  // Please note that everything that should be transitioned
  // needs to be drawn relative to x and y

  display->drawXbm(x + 34, y + 14, WiFi_Logo_width, WiFi_Logo_height, WiFi_Logo_bits);
}

void drawFrame2(OLEDDisplay *display, OLEDDisplayUiState* state, int16_t x, int16_t y) {
  // Demonstrates the 3 included default sizes. The fonts come from SSD1306Fonts.h file
  // Besides the default fonts there will be a program to convert TrueType fonts into this format
  display->setTextAlignment(TEXT_ALIGN_LEFT);
  display->setFont(ArialMT_Plain_10);
  display->drawString(0 + x, 10 + y, "Arial 10");

  display->setFont(ArialMT_Plain_16);
  display->drawString(0 + x, 20 + y, "Arial 16");

  display->setFont(ArialMT_Plain_24);
  display->drawString(0 + x, 34 + y, "Arial 24");
}

void drawFrame3(OLEDDisplay *display, OLEDDisplayUiState* state, int16_t x, int16_t y) {
  // Text alignment demo
  display->setFont(ArialMT_Plain_10);

  // The coordinates define the left starting point of the text
  display->setTextAlignment(TEXT_ALIGN_LEFT);
  display->drawString(0 + x, 11 + y, "Left aligned (0,10)");

  // The coordinates define the center of the text
  display->setTextAlignment(TEXT_ALIGN_CENTER);
  display->drawString(64 + x, 22 + y, "Center aligned (64,22)");

  // The coordinates define the right end of the text
  display->setTextAlignment(TEXT_ALIGN_RIGHT);
  display->drawString(128 + x, 33 + y, "Right aligned (128,33)");
}

void drawFrame4(OLEDDisplay *display, OLEDDisplayUiState* state, int16_t x, int16_t y) {
  // Demo for drawStringMaxWidth:
  // with the third parameter you can define the width after which words will be wrapped.
  // Currently only spaces and "-" are allowed for wrapping
  display->setTextAlignment(TEXT_ALIGN_LEFT);
  display->setFont(ArialMT_Plain_10);
  display->drawStringMaxWidth(0 + x, 10 + y, 128, "Lorem ipsum\n dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore.");
}

void drawFrame5(OLEDDisplay *display, OLEDDisplayUiState* state, int16_t x, int16_t y) {

}

// This array keeps function pointers to all frames
// frames are the single views that slide in
FrameCallback frames[] = { drawFrame1, drawFrame2, drawFrame3, drawFrame4, drawFrame5 };

// how many frames are there?
int frameCount = 5;

// Overlays are statically drawn on top of a frame eg. a clock
OverlayCallback overlays[] = { msOverlay };
int overlaysCount = 1;

void setup() {
  Serial.begin(115200);
  Serial.println();
  Serial.println();

  // The ESP is capable of rendering 60fps in 80Mhz mode
  // but that won't give you much time for anything else
  // run it in 160Mhz mode or just set it to 30 fps
  ui.setTargetFPS(60);

  // Customize the active and inactive symbol
  ui.setActiveSymbol(activeSymbol);
  ui.setInactiveSymbol(inactiveSymbol);

  // You can change this to
  // TOP, LEFT, BOTTOM, RIGHT
  ui.setIndicatorPosition(BOTTOM);

  // Defines where the first frame is located in the bar.
  ui.setIndicatorDirection(LEFT_RIGHT);

  // You can change the transition that is used
  // SLIDE_LEFT, SLIDE_RIGHT, SLIDE_UP, SLIDE_DOWN
  ui.setFrameAnimation(SLIDE_LEFT);

  // Add frames
  ui.setFrames(frames, frameCount);

  // Add overlays
  ui.setOverlays(overlays, overlaysCount);

  // Initialising the UI will init the display too.
  ui.init();

  display.flipScreenVertically();

}


void loop() {
  int remainingTimeBudget = ui.update();

  if (remainingTimeBudget > 0) {
    // You can do some work here
    // Don't do stuff if you are below your
    // time budget.
    delay(remainingTimeBudget);
  }
}


================================================
FILE: examples/SSD1306UiDemo/images.h
================================================
#define WiFi_Logo_width 60
#define WiFi_Logo_height 36
const uint8_t WiFi_Logo_bits[] PROGMEM = {
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0x07, 0x00, 0x00, 0x00,
  0x00, 0x00, 0xE0, 0xFF, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF,
  0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0xFF, 0xFF, 0x00, 0x00, 0x00,
  0x00, 0x00, 0xFE, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF,
  0xFF, 0x03, 0x00, 0x00, 0x00, 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00,
  0x00, 0xFF, 0xFF, 0xFF, 0x07, 0xC0, 0x83, 0x01, 0x80, 0xFF, 0xFF, 0xFF,
  0x01, 0x00, 0x07, 0x00, 0xC0, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x0C, 0x00,
  0xC0, 0xFF, 0xFF, 0x7C, 0x00, 0x60, 0x0C, 0x00, 0xC0, 0x31, 0x46, 0x7C,
  0xFC, 0x77, 0x08, 0x00, 0xE0, 0x23, 0xC6, 0x3C, 0xFC, 0x67, 0x18, 0x00,
  0xE0, 0x23, 0xE4, 0x3F, 0x1C, 0x00, 0x18, 0x00, 0xE0, 0x23, 0x60, 0x3C,
  0x1C, 0x70, 0x18, 0x00, 0xE0, 0x03, 0x60, 0x3C, 0x1C, 0x70, 0x18, 0x00,
  0xE0, 0x07, 0x60, 0x3C, 0xFC, 0x73, 0x18, 0x00, 0xE0, 0x87, 0x70, 0x3C,
  0xFC, 0x73, 0x18, 0x00, 0xE0, 0x87, 0x70, 0x3C, 0x1C, 0x70, 0x18, 0x00,
  0xE0, 0x87, 0x70, 0x3C, 0x1C, 0x70, 0x18, 0x00, 0xE0, 0x8F, 0x71, 0x3C,
  0x1C, 0x70, 0x18, 0x00, 0xC0, 0xFF, 0xFF, 0x3F, 0x00, 0x00, 0x08, 0x00,
  0xC0, 0xFF, 0xFF, 0x1F, 0x00, 0x00, 0x0C, 0x00, 0x80, 0xFF, 0xFF, 0x1F,
  0x00, 0x00, 0x06, 0x00, 0x80, 0xFF, 0xFF, 0x0F, 0x00, 0x00, 0x07, 0x00,
  0x00, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0xF8, 0xFF, 0xFF,
  0xFF, 0x7F, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0xFF, 0x01, 0x00, 0x00,
  0x00, 0x00, 0xFC, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF,
  0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xFF, 0x1F, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x80, 0xFF, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  };

const uint8_t activeSymbol[] PROGMEM = {
    B00000000,
    B00000000,
    B00011000,
    B00100100,
    B01000010,
    B01000010,
    B00100100,
    B00011000
};

const uint8_t inactiveSymbol[] PROGMEM = {
    B00000000,
    B00000000,
    B00000000,
    B00000000,
    B00011000,
    B00011000,
    B00000000,
    B00000000
};


================================================
FILE: keywords.txt
================================================
#######################################
# Syntax Coloring Map List
#######################################


#######################################
# Constants (LITERAL1)
#######################################
INVERSE    LITERAL1

TEXT_ALIGN_LEFT    LITERAL1
TEXT_ALIGN_RIGHT    LITERAL1
TEXT_ALIGN_CENTER    LITERAL1
TEXT_ALIGN_CENTER_BOTH    LITERAL1

GEOMETRY_128_64    LITERAL1
GEOMETRY_128_32    LITERAL1
GEOMETRY_RAWMODE    LITERAL1

ArialMT_Plain_10    LITERAL1
ArialMT_Plain_16    LITERAL1
ArialMT_Plain_24    LITERAL1

SLIDE_UP    LITERAL1
SLIDE_DOWN    LITERAL1
SLIDE_LEFT    LITERAL1
SLIDE_RIGHT    LITERAL1

TOP    LITERAL1
RIGHT    LITERAL1
BOTTOM    LITERAL1
LEFT    LITERAL1

LEFT_RIGHT    LITERAL1
RIGHT_LEFT    LITERAL1

IN_TRANSITION    LITERAL1
FIXED    LITERAL1


#######################################
# Datatypes (KEYWORD1)
#######################################
OLEDDisplay    KEYWORD1
OLEDDisplayUi    KEYWORD1

SH1106Wire    KEYWORD1
SH1106Brzo    KEYWORD1
SH1106Spi    KEYWORD1

SSD1306Wire    KEYWORD1
SSD1306Brzo    KEYWORD1
SSD1306I2C    KEYWORD1
SSD1306Spi    KEYWORD1


#######################################
# Methods and Functions (KEYWORD2)
#######################################
allocateBuffer    KEYWORD2
init    KEYWORD2
resetDisplay    KEYWORD2
setColor    KEYWORD2
getColor    KEYWORD2
setPixel    KEYWORD2
setPixelColor    KEYWORD2
clearPixel    KEYWORD2
drawLine    KEYWORD2
drawRect    KEYWORD2
fillRect    KEYWORD2
drawCircle    KEYWORD2
drawCircleQuads    KEYWORD2
fillCircle    KEYWORD2
fillRing    KEYWORD2
drawHorizontalLine    KEYWORD2
drawVerticalLine    KEYWORD2
drawProgressBar    KEYWORD2
drawFastImage    KEYWORD2
drawXbm    KEYWORD2
drawIco16x16    KEYWORD2
drawString    KEYWORD2
drawStringMaxWidth    KEYWORD2
getStringWidth    KEYWORD2
setTextAlignment    KEYWORD2
setFont    KEYWORD2
setFontTableLookupFunction    KEYWORD2
displayOn    KEYWORD2
displayOff    KEYWORD2
invertDisplay    KEYWORD2
normalDisplay    KEYWORD2
setContrast    KEYWORD2
setBrightness    KEYWORD2
resetOrientation    KEYWORD2
flipScreenVertically    KEYWORD2
mirrorScreen    KEYWORD2
display    KEYWORD2
setLogBuffer    KEYWORD2
drawLogBuffer    KEYWORD2
getWidth    KEYWORD2
getHeight    KEYWORD2


================================================
FILE: library.json
================================================
{
  "name": "ESP8266 and ESP32 OLED driver for SSD1306 displays",
  "version": "4.6.2",
  "keywords": "ssd1306, oled, display, i2c",
  "description": "I2C display driver for SSD1306 OLED displays connected to ESP8266, ESP32, Mbed-OS",
  "license": "MIT",
  "repository":
  {
    "type": "git",
    "url": "https://github.com/ThingPulse/esp8266-oled-ssd1306"
  },
  "authors":
  [
    {
        "name": "Daniel Eichhorn, ThingPulse",
        "email": "squix78@gmail.com",
        "url": "https://thingpulse.com"
    },
    {
        "name": "Fabrice Weinberg",
        "email": "fabrice@weinberg.me"
    }
  ],
  "frameworks": "arduino",
  "platforms": [
    "espressif8266",
    "espressif32",
    "nordicnrf52"
  ]
}


================================================
FILE: library.properties
================================================
name=ESP8266 and ESP32 OLED driver for SSD1306 displays
version=4.6.2
author=ThingPulse, Fabrice Weinberg
maintainer=ThingPulse <info@thingpulse.com>
sentence=I2C display driver for SSD1306 OLED displays connected to ESP8266, ESP32, Mbed-OS
paragraph=The following geometries are currently supported: 128x64, 128x32, 64x48. The init sequence was inspired by Adafruit's library for the same display.
category=Display
url=https://github.com/ThingPulse/esp8266-oled-ssd1306
architectures=esp8266,esp32
license=MIT


================================================
FILE: license
================================================
The MIT License (MIT)

Copyright (c) 2016 by Daniel Eichhorn
Copyright (c) 2016 by Fabrice Weinberg

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

See more at http://blog.squix.ch


================================================
FILE: platformio.ini
================================================
; PlatformIO Project Configuration File
;
;   Build options: build flags, source filter
;   Upload options: custom upload port, speed and extra flags
;   Library options: dependencies, extra library storages
;   Advanced options: extra scripting
;
; Please visit documentation for the other options and examples
; http://docs.platformio.org/page/projectconf.html

[env:d1_mini]
platform = espressif8266
board = d1_mini
framework = arduino
upload_speed = 921600
board_build.f_cpu = 160000000L
upload_port = /dev/cu.SLAB_USBtoUART
monitor_port = /dev/cu.SLAB_USBtoUART
lib_deps =


================================================
FILE: resources/glyphEditor.html
================================================
<!--The MIT License (MIT)

Copyright (c) 2017 by Xavier Grosjean

Based on work 
Copyright (c) 2016 by Daniel Eichhorn
Copyright (c) 2016 by Fabrice Weinberg

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

-->
<!--
 Standalone page to draw icons in matrix and generates the map definition with the format required by 
 library for OLED SD1306 screen: https://github.com/squix78/esp8266-oled-ssd1306
 100% quick and dirty vanilla ECS6, no framework or library was injured for this project.

-->
<html>
  <head>
    <meta charset="utf-8" />
    <style>
      #form, #chars table {
        user-select: none; 
        -moz-user-select: none; 
        margin-top: 5px;
      }
      #chars table, tr, td, th {
        border-collapse: collapse;
      }
      #chars td, th {
        border: 1px solid #CCC;
        width: 12px;
        height: 15px;
      }
      #chars th[action] {
        cursor:pointer;
      }
      #chars th[action="up"], #chars th[action="down"], #chars th[action="left"], #chars th[action="right"] {
        font-size: 10px;
      }
      #chars td.on {
        background-color: #00F;
      }
      
      #addChar, #generate {
        display: none;
      }
      body.started #addChar, body.started #generate {
        display: inline;
      }
      body.started #create {
        display: none;
      }
      #page {
        position:relative;
      }
      #page>div {
        position: relative;
        float: left;
      }

      #output {
        margin-left: 20px;
        margin-top: 12px;
        font-size:12px;
        user-select: all;
        -moz-user-select: all;
        max-width:60%;
      }
      
      #header {
        margin-top: 10px;
      }
      #inputText {
        width: 100%;
        height:120px;
      }
      
    </style>
  </head>
  <body>
    <div id="form">
      <table width="100%">
        <tr>
          <td>Font array name:</td><td><input placeholder="Font array name" type="text" id="name" value="My_Font"/></td>
          <td width="75%" rowspan="5">
            <textarea id="inputText" placeholder="Or paste a char array font definition here">
const uint8_t My_Font[] PROGMEM = {
  0x0A, // Width: 10
  0x0D, // Height: 13
  0x01, // First char: 1
  0x02, // Number of chars: 2
  // Jump Table:
  0x00, 0x00, 0x13, 0x0A, // 1
  0x00, 0x13, 0x14, 0x0A, // 2
  // Font Data:
  0xF0, 0x03, 0x10, 0x02, 0xF0, 0x03, 0x10, 0x02, 0xF0, 0x03, 0x10, 0x02, 0xF0, 0x03, 0x10, 0x02, 0xF0, 0x03, 0xC0, // 1
  0x00, 0x0C, 0x80, 0x0B, 0x70, 0x08, 0x0C, 0x08, 0xF3, 0x0A, 0xF3, 0x0A, 0x0C, 0x08, 0x70, 0x08, 0x80, 0x0B, 0x00, 0x0C, // 2
};              
            </textarea></td>
        </tr>
        <tr>
          <td>First char code:</td><td><input placeholder="First char code" type="number" id="code" value="1" min="1"/></td>
        </tr>
        <tr>
          <td>Width:</td><td><input placeholder="Font width" type="number" id="width" value="10"/></td>
        </tr>
        <tr>
          <td>Height:</td><td><input placeholder="Font height" type="number" id="height" value="13" max="64"/></td>
        </tr>
        <tr>
          <td>NewWidth:</td><td><input placeholder="New Font width" type="number" id="newwidth" value="0"/></td>
        </tr>
        <tr>
          <td>NewHeight:</td><td><input placeholder="New Font height" type="number" id="newheight" value="0" max="64"/></td>
        </tr>
        <tr>
          <td colspan="3"> </td>     <!--slightly improves layout-->
        </tr>
        <tr>
          <td colspan="2">
            <button id="create">Create</button>
            <br/>Shift all
            <button id="shiftUp">Up</button>
            <button id="shiftDown">Down</button>
            <button id="shiftLeft">Left</button>
            <button id="shiftRight">Right</button><br/>
            <button id="generate">Generate</button>
            <button id="savetoFile">Save To File</button>
          </td>
          <td><input type="file" id="fileinput" />  <button id="parse">Parse</button></td>
        </tr>
      </table>
      <br/>
    </div>
    <div id="page">
      <div id="charxContainer" ondragstart="return false;">
        <div id="chars"></div><br/>
        <button id="addChar">Add a character</button>
      </div>
      <div id="output">
        <div class="output" id="header"> </div>
        <div class="output" id="jump"> </div>
        <div class="output" id="data"> </div>
      </div>
    </div>
    <script>
    (function() {
      let font;
      
      class Font {
        constructor() {
          this.height = parseInt(document.getElementById('height').value);
          this.width = parseInt(document.getElementById('width').value);
          this.currentCharCode = parseInt(document.getElementById('code').value);
          this.fontContainer = document.getElementById('chars');
          this.bytesForHeight = (1 + ((this.height - 1) >> 3));  // number of bytes needed for this font height
          document.body.className = "started";
          document.getElementById('height').disabled = true;
          document.getElementById('width').disabled = true;          
        }
        
        // Should we have a Char and a Pixel class ? not sure it's worth it.
        // Let's use the DOM to store everything for now
        
        static updateCaption(element, code) {
          element.textContent = `Char #${code} [`+String.fromCharCode(code)+']';
        }
        
        // Add a pixel matrix to draw a new character
        // jumpaData not used for now: some day, use the last byte for optimisation 
        addChar(jumpData, charData) {
          let charContainer = this.fontContainer.appendChild(document.createElement("table"));
          charContainer.setAttribute("code", this.currentCharCode);
          let caption = charContainer.appendChild(document.createElement("caption"));
          Font.updateCaption(caption, this.currentCharCode);
          let header = charContainer.appendChild(document.createElement("tr"));
          header.innerHTML = '<th  title="Delete this char" action="delete">&cross;</th>'
              + '<th title="Add a char above" action="add">+</th>'
              + '<th title="Shift pixels to the left" action="left">&larr;</th>'
              + '<th title="Shift pixels down" action="down">&darr;</th>'
              + '<th title="Shift pixels up" action="up">&uarr;</th>'
              + '<th title="Shift pixels to the right" action="right">&rarr;</th>'
              + '<th title="Copy from another character" action="copy">&copy;</th>'
              + '<th title="Reset all pixels" action="clean">&empty;</th>';
          // If data is provided, decode it to pixel initialization friendly structure
          let pixelInit = [];
          if (charData && charData.length) {
            // charData byte count needs to be a multiple of bytesForHeight. End bytes with value 0 may have been trimmed
            let missingBytes = charData.length % this.bytesForHeight;
            for(let b = 0; b < missingBytes ; b++) {
              charData.push(0);
            }
            while(charData.length) {
              let row = charData.splice(0, this.bytesForHeight).reverse();
              let pixelRow = [];
              for (let b = 0; b < row.length; b++) {
                let mask = 0x80;
                let byte = row[b];
                for (let bit = 0; bit < 8; bit++) {
                  if (byte & mask) {
                    pixelRow.push(1);
                  } else {
                    pixelRow.push(0);
                  }
                  mask = mask >> 1;
                }
              }
              pixelRow.splice(0, pixelRow.length - this.height);
              //Font.output('data', pixelRow);
              pixelInit.push(pixelRow.reverse());
            }
          }
          
          for(let r = 0; r < this.height; r++) {
          	let rowContainer = charContainer.appendChild(document.createElement("tr"));
            for(let c = 0; c < this.width; c++) {
          		let pixContainer = rowContainer.appendChild(document.createElement("td"));
              pixContainer.setAttribute('action', 'toggle');
          		// If there is some init data, set the pixel accordingly
              if (pixelInit.length && pixelInit[c]) {
                if (pixelInit[c][r]) {
                  pixContainer.className = 'on';
                }
              }          		
            }
          }
          this.currentCharCode++;
          return charContainer;
        }
        
        static togglePixel(pixel) {
          pixel.className = pixel.className === 'on' ? '': 'on';
        }
        
        // Return anInt as hex string
        static toHexString(aByte) {
          let zero = aByte < 16?'0':'';
          return `0x${zero}${aByte.toString(16).toUpperCase()}`
        }
        
        // Return least significant byte as hex string
        static getLsB(anInt) {
          return Font.toHexString(anInt & 0xFF);      
        }
        // Return most significant byte as hex string
        static getMsB(anInt) {
          return Font.toHexString(anInt>>>8);      
        }
       
        static output(targetId, msg) {
          let output = document.getElementById(targetId);
          let line = output.appendChild(document.createElement('div'));
          line.textContent = msg;
        }
        static emptyChars() {
          document.getElementById('chars').textContent = '';
        }
        static emptyOutput() {
          document.getElementById('header').textContent = '';
          document.getElementById('jump').textContent = '';
          document.getElementById('data').textContent = '';
        }
		
        saveFile() {
          let filename = document.getElementById('name').value.replace(/[^a-zA-Z0-9_$]/g, '_') + ".h";
          let data = document.getElementById("output").innerText;
          if(data.length < 10) return;
          let blobObject = new Blob([data], {type:'text/plain'}); 
    
          if(window.navigator.msSaveBlob) {
            window.navigator.msSaveBlob(blobObject, filename);
          } else {
            let a = document.createElement("a");
            a.setAttribute("href", URL.createObjectURL(blobObject));
            a.setAttribute("download", filename);
            if (document.createEvent) {
              let event = document.createEvent('MouseEvents');
              event.initEvent('click', true, true);
              a.dispatchEvent(event);
            } else {
              a.click();
            }
          }  
        }
			
        // Read from the <td> css class the pixels that need to be on
        // generates the jump table and font data 
        generate() {
          // this.width -= 3;  // hack to narrow an existing font
          var newheight = parseInt(document.getElementById('newheight').value);
          if(newheight){
            this.height = newheight;
            this.bytesForHeight = (1 + ((this.height - 1) >> 3));
          }
          var newwidth = parseInt(document.getElementById('newwidth').value);
          if(newwidth){
             this.width = newwidth;	
          }

          Font.emptyOutput();
          let chars = this.fontContainer.getElementsByTagName('table');
          let firstCharCode = parseInt(document.getElementById('code').value);
          let name = document.getElementById('name').value.replace(/[^a-zA-Z0-9_$]/g, '_');
          
          let bits2add = this.bytesForHeight*8 - this.height;  // number of missing bits to fill leftmost byte
          let charCount = chars.length;
          let charAddr = 0;
          // Comments are used when parsing back a generated font
          Font.output('jump', '  // Jump Table:');
          Font.output('data', '  // Font Data:');
          // Browse each character
          for(let ch = 0; ch < charCount; ch++) {
            // Fix renumbering in case first char code was modified  
            Font.updateCaption(chars[ch].getElementsByTagName('caption')[0], ch + firstCharCode);
            let charBytes = [];
            let charCode = ch + firstCharCode;
            let rows = chars[ch].getElementsByTagName('tr');
            let charNotZero = false;
            // Browse each column
            for(let col = 0; col < this.width ; col++) {
              let bits = ""; // using string because js uses 32b ints when performing bit operations
              // Browse each row starting from the bottom one, going up, and accumulate pixels in
              // a string: this rotates the glyph
              // Beware, row 0 is table headers.
          //for(let r = rows.length-1; r >=1 ; r--) {

              for(let r = this.height; r >=1 ; r--) {
                let pixelState = rows[r].children[col].className;
                bits += (pixelState === 'on' ? '1': '0');           
              }
              // Need to complete missing bits to have a sizeof byte multiple number of bits
              for(let b = 0; b < bits2add; b++) {
                bits =  '0' + bits;
              }
              // Font.output('data', `  // ${bits}`);  // Debugging help: rotated bitmap

              // read bytes from the end
              for(let b = bits.length - 1; b >= 7; b -= 8) {
                //Font.output('data', `  // ${bits.substr(b-7, 8)}`);  // Debugging help: rotated bitmap
                let byte = parseInt(bits.substr(b-7, 8), 2);
                if (byte !== 0) {
                  charNotZero = true;
                }
                charBytes.push(Font.toHexString(byte));
              } 
            }
            // Compute the used width of the character:  
            // rightmost column with pixels plus one
            // one column is spread over several bytes...
            let charWidth = 0;
            for(let i=charBytes.length - 1; i >= 0; i-=this.bytesForHeight) {
              let sum = 0;
              for(let j=0; j < this.bytesForHeight; j++) {
                sum += parseInt(charBytes[i - j], 16);
              }
              if(sum !== 0) {
                charWidth = (i + 1)/this.bytesForHeight + 1;
                break;
              }
            }

            // Memory optim: Remove bytes with value 0 at the end of the array.
            while(parseInt(charBytes[charBytes.length-1], 16) === 0 && charBytes.length > 1) {
              charBytes.pop();
            }
            if (charNotZero) {
              Font.output('data', `  ${charBytes.join(', ')},  // ${charCode}`);
              Font.output('jump', `  ${Font.getMsB(charAddr)}, ${Font.getLsB(charAddr)}, ${Font.toHexString(charBytes.length)}, ${Font.toHexString(charWidth)},  // ${charCode} `);
              charAddr += charBytes.length;
            } else {
              Font.output('jump', `  0xFF, 0xFF, 0x00, ${Font.toHexString(this.width)},  // ${charCode} `);
            }
          }
          Font.output('data', '};');
          
          Font.output('header', "// Font generated or edited with the glyphEditor");
          Font.output('header', `const uint8_t ${name}[] PROGMEM = {`);
          // Comments are used when parsing back a generated font
          Font.output('header', `  ${Font.toHexString(this.width)}, // Width: ${this.width}`);
          Font.output('header', `  ${Font.toHexString(this.height)}, // Height: ${this.height}`);          
          Font.output('header', `  ${Font.toHexString(firstCharCode)}, // First char: ${firstCharCode}`);
          Font.output('header', `  ${Font.toHexString(charCount)}, // Number of chars: ${charCount}`);
        }
      }
	  
      document.getElementById('fileinput').addEventListener('change', function(e) {
        let f = e.target.files[0]; 
        if (f) {
          let r = new FileReader();
          r.onload = function(e) { 
            let contents = e.target.result;
                alert( "Got the file.\n" 
                +"name: " + f.name + "\n"
                +"type: " + f.type + "\n"
                +"size: " + f.size + " bytes\n"
                +"starts with: " + contents.substr(0, contents.indexOf("\n")) 
            );
              document.getElementById("inputText").value = contents;
          };
          r.readAsText(f);
        } else { 
          alert("Failed to load file");
        }
        });
      
      document.getElementById('savetoFile').addEventListener('click', function() {
        font.saveFile();
      });
      
      document.getElementById('shiftUp').addEventListener('click', function() {
        var chars = document.getElementById("chars");
        var tables = chars.getElementsByTagName("table");
        for(var i=0; i< tables.length; i++) {
          shiftUp(tables[i]);
        }
      });
      
      document.getElementById('shiftDown').addEventListener('click', function() {
        var chars = document.getElementById("chars");
        var tables = chars.getElementsByTagName("table");
        for(var i=0; i< tables.length; i++) {
          shiftDown(tables[i]);
        }
      });
      document.getElementById('shiftLeft').addEventListener('click', function() {
        var chars = document.getElementById("chars");
        var tables = chars.getElementsByTagName("table");
        for(var i=0; i< tables.length; i++) {
          shiftLeft(tables[i]);
        }
      });
      document.getElementById('shiftRight').addEventListener('click', function() {
        var chars = document.getElementById("chars");
        var tables = chars.getElementsByTagName("table");
        for(var i=0; i< tables.length; i++) {
          shiftRight(tables[i]);
        }
      });
      
      document.getElementById('generate').addEventListener('click', function() {
        font.generate();
      });
      document.getElementById('addChar').addEventListener('click', function() {
        font.addChar();
      });
      document.getElementById('inputText').addEventListener('click', function(e) {
        let target = e.target;
        target.select();
      });
      document.getElementById('chars').addEventListener('mousedown', function(e) {
        if (e.button !== 0) return;
        let target = e.target;
        let action = target.getAttribute('action') || '';
        if (action === '') return;
        let result, code, nextContainer, previousContainer, pixels ;
        let currentContainer = target.parentNode.parentNode;
        switch(action) {
          case 'add':
            code = currentContainer.getAttribute('code');
            nextContainer = font.addChar();
            currentContainer.parentNode.insertBefore(nextContainer, currentContainer);
            do {
              nextContainer.setAttribute('code', code);
              Font.updateCaption(nextContainer.getElementsByTagName('caption')[0], code);
              code ++;
            } while (nextContainer = nextContainer.nextSibling);
            break;

          case 'delete':
            result = confirm("Delete this character ?");
            if (!result) return;
            code = currentContainer.getAttribute('code');
            nextContainer = currentContainer;
            while (nextContainer = nextContainer.nextSibling) {
              nextContainer.setAttribute('code', code);
              Font.updateCaption(nextContainer.getElementsByTagName('caption')[0], code);
              code ++;
            }
            currentContainer.parentNode.removeChild(currentContainer);
            break;

          // Shift pixels to the left  
          case 'left':
            shiftLeft(currentContainer);
            break;
          
          // Shift pixels to the right
          case 'right':
            shiftRight(currentContainer);
            break;

          // Shift pixels down
          case 'down':
            shiftDown(currentContainer);
			break;

          // Shift pixels up
          case 'up':
            shiftUp(currentContainer);
            break;

          case 'toggle':
            Font.togglePixel(target);
            break;

          case 'clean':
            result = confirm("Delete the pixels ?");
            if (!result) return;
            pixels = currentContainer.getElementsByTagName('td');
            for (let p = 0; p < pixels.length; p++) {
              pixels[p].className = '';
            }
            break;
          
          case 'copy':
             let charNumber = parseInt(prompt("Source char #: "));
             let chars = font.fontContainer.getElementsByTagName('table');
             let tableOffset = charNumber - parseInt(document.getElementById('code').value);
             let srcPixels = chars[tableOffset].getElementsByTagName('td');
             let targetPixels = currentContainer.getElementsByTagName('td');
             for(let i=0; i < srcPixels.length; i++) {
               // First tds are in the th row, for editing actions. Skip them
               if (targetPixels[i].parentNode.localName === 'th') continue; // In case we give them css at some point...
               targetPixels[i].className = srcPixels[i].className;
             }
            break;
          default:
            // no.
        }
        
      });
      function shiftUp(container) {
        var pixels = container.getElementsByTagName('td');
        for(p = 0; p < pixels.length; p++) {
          if(p < font.width*(font.height -1)) {
            pixels[p].className = pixels[p + font.width].className;
          } else {
            pixels[p].className = '';
          }
        }  
      }
      function shiftDown(container) {
        var pixels = container.getElementsByTagName('td');
        for(p = pixels.length-1; p >=0 ; p--) {
          if(p >= font.width) {
           pixels[p].className = pixels[p - font.width].className;
          } else {
           pixels[p].className = '';
          }
        } 
      }
      function shiftLeft(container) {
        var pixels = container.getElementsByTagName('td');
        for(p = 0; p < pixels.length; p++) {
          if((p + 1) % font.width) {
             pixels[p].className = pixels[p + 1].className;
          } else {
             pixels[p].className = '';
          }
        }
      }
      
      function shiftRight(container) {
        var pixels = container.getElementsByTagName('td');
        for(p = pixels.length-1; p >=0 ; p--) {
          if(p % font.width) {
            pixels[p].className = pixels[p - 1].className;
          } else {
            pixels[p].className = '';
          }
        }
      }
      
      document.getElementById('chars').addEventListener('mouseover', function(e) {
        let target = e.target;
        let action = target.getAttribute('action');
        if (action !== 'toggle' || e.buttons !== 1) return;
        Font.togglePixel(target);
      });
      document.getElementById('chars').addEventListener('dragstart', function() {
        return false;
      });

      document.getElementById('create').addEventListener('click', function() {
      	font = new Font();
        font.addChar();
      });

      // parse a char array declaration for an existing font.
      // parsing heavily relies on comments.
      document.getElementById('parse').addEventListener('click', function() {
        if (document.getElementById('chars').childElementCount) {
          let result = confirm("Confirm you want to overwrite the existing grids ?");
          if (!result) return;          
        } 
        let lines = document.getElementById('inputText').value.split('\n');
        let name = '';
        let height = 0;
        let width = 0;
        let firstCharCode = 0;
        let jumpTable = [];
        let charData = [];
        let readingJumpTable = false;
        let readingData = false;
        
        for(let l = 0 ; l < lines.length; l++) {
          // TODO ? keep C compilation directives to copy them (not lowercased :)) to newly generated char array
          let line = lines[l].trim();
          //alert(line);
          let fields;

          // Declaration line: grab the name
          if (line.indexOf('PROGMEM') > 0) {
            fields = line.split(' ');
            name = fields[2].replace(/[\[\]]/g, '');
            continue;
          }
          line = line.toLowerCase();
          // Todo: could rely on line order...
          // width line: grab the width
          if (line.indexOf('width') > 0) {
            fields = line.split(',');
            width = fields[0];
            continue;
          }
          // height line: grab the height 
          if (line.indexOf('height') > 0) {
            fields = line.split(',');
            height = fields[0];
            continue;
          }
          // first char code line: grab the first char code 
          if (line.indexOf('first char') > 0) {
            fields = line.split(',');
            firstCharCode = fields[0];
            continue;
          }
          // End of array declaration
          // TODO warn if more lines: next fonts are ignored
          if (line.indexOf('};') === 0) {
            break;
          }
          
          if (readingJumpTable || readingData) {
            if (line.indexOf('#') !== 0 && line.length !== 0 && line.indexOf('//') !== 0) {
              line = line.replace(/\/\/.*/, ''); // get rid of end of line comments
              fields = line.split(',');
              let newEntry = [];
              for(let f=0; f < fields.length; f++) {
                let value = parseInt(fields[f]);
                if (isNaN(value)) continue;
                if (readingData) {
                  charData.push(value);
                }
                if (readingJumpTable) {
                  newEntry.push(value);
                }
              }
              if (readingJumpTable) {
                jumpTable.push(newEntry);
              }
            }            
          }
          
          // Begining of data
          if (line.indexOf('font data') > 0) {
            readingData = true;
            readingJumpTable = false;
          }
          // Begining of jump table
          if (line.indexOf('jump table') > 0) {
            readingJumpTable = true;
          }
        }
        if (!name || !height || !width || !firstCharCode) {
          alert("Does not look like a parsable font. Try again.");
          return;
        }
        
        Font.emptyChars();
        Font.emptyOutput();
        document.getElementById('name').value = name;
        document.getElementById('height').value = parseInt(height);
        document.getElementById('width').value = parseInt(width);
        document.getElementById('code').value = parseInt(firstCharCode);
      	font = new Font();
      	for(let c = 0 ; c < jumpTable.length; c++) {
      	  let jumpEntry = jumpTable[c];
      	  let charEntry = [];
      	  // displayable character 
      	  if (jumpEntry[0] !== 255 || jumpEntry[1] !== 255) {
      	    charEntry = charData.splice(0, jumpEntry[2]);
          }
      	  font.addChar(jumpEntry, charEntry);
        }
        document.body.className = "started";
      });        
      
      })();
    </script>  
  </body>
</html>


================================================
FILE: src/OLEDDisplay.cpp
================================================
/**
 * The MIT License (MIT)
 *
 * 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
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 *
 * ThingPulse invests considerable time and money to develop these open source libraries.
 * Please support us by buying our products (and not the clones) from
 * https://thingpulse.com
 *
 */

 /*
  * TODO Helmut
  * - test/finish dislplay.printf() on mbed-os
  */

#include "OLEDDisplay.h"

OLEDDisplay::OLEDDisplay() {

	displayWidth = 128;
	displayHeight = 64;
	displayBufferSize = displayWidth * displayHeight / 8;
  inhibitDrawLogBuffer = false;
	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::allocateBuffer() {

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

  if (!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) + BufferOffset);
    this->buffer += BufferOffset;

    if(!this->buffer) {
      DEBUG_OLEDDISPLAY("[OLEDDISPLAY][init] Not enough memory to create display\n");
      return false;
    }
  }

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

    if(!this->buffer_back) {
      DEBUG_OLEDDISPLAY("[OLEDDISPLAY][init] Not enough memory to create back buffer\n");
      free(this->buffer - BufferOffset);
      return false;
    }
  }
  #endif

  return true;
}

bool OLEDDisplay::init() {

  BufferOffset = getBufferOffset();

  if(!allocateBuffer()) {
    return false;
  }

  sendInitCommands();
  resetDisplay();

  return true;
}

void OLEDDisplay::end() {
  if (this->buffer) { free(this->buffer - BufferOffset); this->buffer = NULL; }
  #ifdef OLEDDISPLAY_DOUBLE_BUFFER
  if (this->buffer_back) { free(this->buffer_back - BufferOffset); this->buffer_back = NULL; }
  #endif
  if (this->logBuffer != NULL) { free(this->logBuffer); this->logBuffer = NULL; }
}

void OLEDDisplay::resetDisplay(void) {
  clear();
  #ifdef OLEDDISPLAY_DOUBLE_BUFFER
  memset(buffer_back, 1, displayBufferSize);
  #endif
  display();
}

void OLEDDisplay::setColor(OLEDDISPLAY_COLOR color) {
  this->color = color;
}

OLEDDISPLAY_COLOR OLEDDisplay::getColor() {
  return this->color;
}

void OLEDDisplay::setPixel(int16_t x, int16_t y) {
  if (x >= 0 && x < this->width() && y >= 0 && y < this->height()) {
    switch (color) {
      case WHITE:   buffer[x + (y / 8) * this->width()] |=  (1 << (y & 7)); break;
      case BLACK:   buffer[x + (y / 8) * this->width()] &= ~(1 << (y & 7)); break;
      case INVERSE: buffer[x + (y / 8) * this->width()] ^=  (1 << (y & 7)); break;
    }
  }
}

void OLEDDisplay::setPixelColor(int16_t x, int16_t y, OLEDDISPLAY_COLOR color) {
  if (x >= 0 && x < this->width() && y >= 0 && y < this->height()) {
    switch (color) {
      case WHITE:   buffer[x + (y / 8) * this->width()] |=  (1 << (y & 7)); break;
      case BLACK:   buffer[x + (y / 8) * this->width()] &= ~(1 << (y & 7)); break;
      case INVERSE: buffer[x + (y / 8) * this->width()] ^=  (1 << (y & 7)); break;
    }
  }
}

void OLEDDisplay::clearPixel(int16_t x, int16_t y) {
  if (x >= 0 && x < this->width() && y >= 0 && y < this->height()) {
    switch (color) {
      case BLACK:   buffer[x + (y >> 3) * this->width()] |=  (1 << (y & 7)); break;
      case WHITE:   buffer[x + (y >> 3) * this->width()] &= ~(1 << (y & 7)); break;
      case INVERSE: buffer[x + (y >> 3) * this->width()] ^=  (1 << (y & 7)); break;
    }
  }
}


// Bresenham's algorithm - thx wikipedia and Adafruit_GFX
void OLEDDisplay::drawLine(int16_t x0, int16_t y0, int16_t x1, int16_t y1) {
  int16_t steep = abs(y1 - y0) > abs(x1 - x0);
  if (steep) {
    _swap_int16_t(x0, y0);
    _swap_int16_t(x1, y1);
  }

  if (x0 > x1) {
    _swap_int16_t(x0, x1);
    _swap_int16_t(y0, y1);
  }

  int16_t dx, dy;
  dx = x1 - x0;
  dy = abs(y1 - y0);

  int16_t err = dx / 2;
  int16_t ystep;

  if (y0 < y1) {
    ystep = 1;
  } else {
    ystep = -1;
  }

  for (; x0<=x1; x0++) {
    if (steep) {
      setPixel(y0, x0);
    } else {
      setPixel(x0, y0);
    }
    err -= dy;
    if (err < 0) {
      y0 += ystep;
      err += dx;
    }
  }
}

void OLEDDisplay::drawRect(int16_t x, int16_t y, int16_t width, int16_t height) {
  drawHorizontalLine(x, y, width);
  drawVerticalLine(x, y, height);
  drawVerticalLine(x + width - 1, y, height);
  drawHorizontalLine(x, y + height - 1, width);
}

void OLEDDisplay::fillRect(int16_t xMove, int16_t yMove, int16_t width, int16_t height) {
  for (int16_t x = xMove; x < xMove + width; x++) {
    drawVerticalLine(x, yMove, height);
  }
}

void OLEDDisplay::drawCircle(int16_t x0, int16_t y0, int16_t radius) {
  int16_t x = 0, y = radius;
	int16_t dp = 1 - radius;
	do {
		if (dp < 0)
			dp = dp + (x++) * 2 + 3;
		else
			dp = dp + (x++) * 2 - (y--) * 2 + 5;

		setPixel(x0 + x, y0 + y);     //For the 8 octants
		setPixel(x0 - x, y0 + y);
		setPixel(x0 + x, y0 - y);
		setPixel(x0 - x, y0 - y);
		setPixel(x0 + y, y0 + x);
		setPixel(x0 - y, y0 + x);
		setPixel(x0 + y, y0 - x);
		setPixel(x0 - y, y0 - x);

	} while (x < y);

  setPixel(x0 + radius, y0);
  setPixel(x0, y0 + radius);
  setPixel(x0 - radius, y0);
  setPixel(x0, y0 - radius);
}

void OLEDDisplay::drawCircleQuads(int16_t x0, int16_t y0, int16_t radius, uint8_t quads) {
  int16_t x = 0, y = radius;
  int16_t dp = 1 - radius;
  while (x < y) {
    if (dp < 0)
      dp = dp + (x++) * 2 + 3;
    else
      dp = dp + (x++) * 2 - (y--) * 2 + 5;
    if (quads & 0x1) {
      setPixel(x0 + x, y0 - y);
      setPixel(x0 + y, y0 - x);
    }
    if (quads & 0x2) {
      setPixel(x0 - y, y0 - x);
      setPixel(x0 - x, y0 - y);
    }
    if (quads & 0x4) {
      setPixel(x0 - y, y0 + x);
      setPixel(x0 - x, y0 + y);
    }
    if (quads & 0x8) {
      setPixel(x0 + x, y0 + y);
      setPixel(x0 + y, y0 + x);
    }
  }
  if (quads & 0x1 && quads & 0x8) {
    setPixel(x0 + radius, y0);
  }
  if (quads & 0x4 && quads & 0x8) {
    setPixel(x0, y0 + radius);
  }
  if (quads & 0x2 && quads & 0x4) {
    setPixel(x0 - radius, y0);
  }
  if (quads & 0x1 && quads & 0x2) {
    setPixel(x0, y0 - radius);
  }
}


void OLEDDisplay::fillCircle(int16_t x0, int16_t y0, int16_t radius) {
  int16_t x = 0, y = radius;
	int16_t dp = 1 - radius;
	do {
		if (dp < 0)
      dp = dp + (x++) * 2 + 3;
    else
      dp = dp + (x++) * 2 - (y--) * 2 + 5;

    drawHorizontalLine(x0 - x, y0 - y, 2*x);
    drawHorizontalLine(x0 - x, y0 + y, 2*x);
    drawHorizontalLine(x0 - y, y0 - x, 2*y);
    drawHorizontalLine(x0 - y, y0 + x, 2*y);


	} while (x < y);
  drawHorizontalLine(x0 - radius, y0, 2 * radius);

}

void OLEDDisplay::drawTriangle(int16_t x0, int16_t y0, int16_t x1, int16_t y1,
                               int16_t x2, int16_t y2) {
  drawLine(x0, y0, x1, y1);
  drawLine(x1, y1, x2, y2);
  drawLine(x2, y2, x0, y0);
}

void OLEDDisplay::fillTriangle(int16_t x0, int16_t y0, int16_t x1, int16_t y1,
                               int16_t x2, int16_t y2) {
  int16_t a, b, y, last;

  if (y0 > y1) {
    _swap_int16_t(y0, y1);
    _swap_int16_t(x0, x1);
  }
  if (y1 > y2) {
    _swap_int16_t(y2, y1);
    _swap_int16_t(x2, x1);
  }
  if (y0 > y1) {
    _swap_int16_t(y0, y1);
    _swap_int16_t(x0, x1);
  }

  if (y0 == y2) {
    a = b = x0;
    if (x1 < a) {
      a = x1;
    } else if (x1 > b) {
      b = x1;
    }
    if (x2 < a) {
      a = x2;
    } else if (x2 > b) {
      b = x2;
    }
    drawHorizontalLine(a, y0, b - a + 1);
    return;
  }

  int16_t
    dx01 = x1 - x0,
    dy01 = y1 - y0,
    dx02 = x2 - x0,
    dy02 = y2 - y0,
    dx12 = x2 - x1,
    dy12 = y2 - y1;
  int32_t
    sa   = 0,
    sb   = 0;

  if (y1 == y2) {
    last = y1; // Include y1 scanline
  } else {
    last = y1 - 1; // Skip it
  }

  for (y = y0; y <= last; y++) {
    a = x0 + sa / dy01;
    b = x0 + sb / dy02;
    sa += dx01;
    sb += dx02;

    if (a > b) {
      _swap_int16_t(a, b);
    }
    drawHorizontalLine(a, y, b - a + 1);
  }

  sa = dx12 * (y - y1);
  sb = dx02 * (y - y0);
  for (; y <= y2; y++) {
    a = x1 + sa / dy12;
    b = x0 + sb / dy02;
    sa += dx12;
    sb += dx02;

    if (a > b) {
      _swap_int16_t(a, b);
    }
    drawHorizontalLine(a, y, b - a + 1);
  }
}

void OLEDDisplay::drawHorizontalLine(int16_t x, int16_t y, int16_t length) {
  if (y < 0 || y >= this->height()) { return; }

  if (x < 0) {
    length += x;
    x = 0;
  }

  if ( (x + length) > this->width()) {
    length = (this->width() - x);
  }

  if (length <= 0) { return; }

  uint8_t * bufferPtr = buffer;
  bufferPtr += (y >> 3) * this->width();
  bufferPtr += x;

  uint8_t drawBit = 1 << (y & 7);

  switch (color) {
    case WHITE:   while (length--) {
        *bufferPtr++ |= drawBit;
      }; break;
    case BLACK:   drawBit = ~drawBit;   while (length--) {
        *bufferPtr++ &= drawBit;
      }; break;
    case INVERSE: while (length--) {
        *bufferPtr++ ^= drawBit;
      }; break;
  }
}

void OLEDDisplay::drawVerticalLine(int16_t x, int16_t y, int16_t length) {
  if (x < 0 || x >= this->width()) return;

  if (y < 0) {
    length += y;
    y = 0;
  }

  if ( (y + length) > this->height()) {
    length = (this->height() - y);
  }

  if (length <= 0) return;


  uint8_t yOffset = y & 7;
  uint8_t drawBit;
  uint8_t *bufferPtr = buffer;

  bufferPtr += (y >> 3) * this->width();
  bufferPtr += x;

  if (yOffset) {
    yOffset = 8 - yOffset;
    drawBit = ~(0xFF >> (yOffset));

    if (length < yOffset) {
      drawBit &= (0xFF >> (yOffset - length));
    }

    switch (color) {
      case WHITE:   *bufferPtr |=  drawBit; break;
      case BLACK:   *bufferPtr &= ~drawBit; break;
      case INVERSE: *bufferPtr ^=  drawBit; break;
    }

    if (length < yOffset) return;

    length -= yOffset;
    bufferPtr += this->width();
  }

  if (length >= 8) {
    switch (color) {
      case WHITE:
      case BLACK:
        drawBit = (color == WHITE) ? 0xFF : 0x00;
        do {
          *bufferPtr = drawBit;
          bufferPtr += this->width();
          length -= 8;
        } while (length >= 8);
        break;
      case INVERSE:
        do {
          *bufferPtr = ~(*bufferPtr);
          bufferPtr += this->width();
          length -= 8;
        } while (length >= 8);
        break;
    }
  }

  if (length > 0) {
    drawBit = (1 << (length & 7)) - 1;
    switch (color) {
      case WHITE:   *bufferPtr |=  drawBit; break;
      case BLACK:   *bufferPtr &= ~drawBit; break;
      case INVERSE: *bufferPtr ^=  drawBit; break;
    }
  }
}

void OLEDDisplay::drawProgressBar(uint16_t x, uint16_t y, uint16_t width, uint16_t height, uint8_t progress) {
  uint16_t radius = height / 2;
  uint16_t xRadius = x + radius;
  uint16_t yRadius = y + radius;
  uint16_t doubleRadius = 2 * radius;
  uint16_t innerRadius = radius - 2;

  setColor(WHITE);
  drawCircleQuads(xRadius, yRadius, radius, 0b00000110);
  drawHorizontalLine(xRadius, y, width - doubleRadius + 1);
  drawHorizontalLine(xRadius, y + height, width - doubleRadius + 1);
  drawCircleQuads(x + width - radius, yRadius, radius, 0b00001001);

  uint16_t maxProgressWidth = (width - doubleRadius + 1) * progress / 100;

  fillCircle(xRadius, yRadius, innerRadius);
  fillRect(xRadius + 1, y + 2, maxProgressWidth, height - 3);
  fillCircle(xRadius + maxProgressWidth, yRadius, innerRadius);
}

void OLEDDisplay::drawFastImage(int16_t xMove, int16_t yMove, int16_t width, int16_t height, const uint8_t *image) {
  drawInternal(xMove, yMove, width, height, image, 0, 0);
}

void OLEDDisplay::drawXbm(int16_t xMove, int16_t yMove, int16_t width, int16_t height, const uint8_t *xbm) {
  int16_t widthInXbm = (width + 7) / 8;
  uint8_t data = 0;

  for(int16_t y = 0; y < height; y++) {
    for(int16_t x = 0; x < width; x++ ) {
      if (x & 7) {
        data >>= 1; // Move a bit
      } else {  // Read new data every 8 bit
        data = pgm_read_byte(xbm + (x / 8) + y * widthInXbm);
      }
      // if there is a bit draw it
      if (data & 0x01) {
        setPixel(xMove + x, yMove + y);
      }
    }
  }
}

void OLEDDisplay::drawIco16x16(int16_t xMove, int16_t yMove, const uint8_t *ico, bool inverse) {
  uint16_t data;

  for(int16_t y = 0; y < 16; y++) {
    data = pgm_read_byte(ico + (y << 1)) + (pgm_read_byte(ico + (y << 1) + 1) << 8);
    for(int16_t x = 0; x < 16; x++ ) {
      if ((data & 0x01) ^ inverse) {
        setPixelColor(xMove + x, yMove + y, WHITE);
      } else {
        setPixelColor(xMove + x, yMove + y, BLACK);
      }
      data >>= 1; // Move a bit
    }
  }
}

uint16_t OLEDDisplay::drawStringInternal(int16_t xMove, int16_t yMove, const char* text, uint16_t textLength, uint16_t textWidth, bool utf8) {
  uint8_t textHeight       = pgm_read_byte(fontData + HEIGHT_POS);
  uint8_t firstChar        = pgm_read_byte(fontData + FIRST_CHAR_POS);
  uint16_t sizeOfJumpTable = pgm_read_byte(fontData + CHAR_NUM_POS)  * JUMPTABLE_BYTES;

  uint16_t cursorX         = 0;
  uint16_t cursorY         = 0;
  uint16_t charCount       = 0;

  switch (textAlignment) {
    case TEXT_ALIGN_CENTER_BOTH:
      yMove -= textHeight >> 1;
    // Fallthrough
    case TEXT_ALIGN_CENTER:
      xMove -= textWidth >> 1; // divide by 2
      break;
    case TEXT_ALIGN_RIGHT:
      xMove -= textWidth;
      break;
    case TEXT_ALIGN_LEFT:
      break;
  }

  // Don't draw anything if it is not on the screen.
  if (xMove + textWidth  < 0 || xMove >= this->width() ) {return 0;}
  if (yMove + textHeight < 0 || yMove >= this->height()) {return 0;}

  for (uint16_t j = 0; j < textLength; j++) {
    int16_t xPos = xMove + cursorX;
    int16_t yPos = yMove + cursorY;
    if (xPos > this->width())
      break; // no need to continue
    charCount++;

    uint8_t code;
    if (utf8) {
      code = (this->fontTableLookupFunction)(text[j]);
      if (code == 0)
        continue;
    } else
      code = text[j];
    if (code >= firstChar) {
      uint8_t charCode = code - firstChar;

      // 4 Bytes per char code
      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)) {
        // Get the position of the char data
        uint16_t charDataPosition = JUMPTABLE_START + sizeOfJumpTable + ((msbJumpToChar << 8) + lsbJumpToChar);
        drawInternal(xPos, yPos, currentCharWidth, textHeight, fontData, charDataPosition, charByteSize);
      }

      cursorX += currentCharWidth;
    }
  }
  return charCount;
}


uint16_t OLEDDisplay::drawString(int16_t xMove, int16_t yMove, const String &strUser) {
  uint16_t lineHeight = pgm_read_byte(fontData + HEIGHT_POS);

  // char* text must be freed!
  char* text = strdup(strUser.c_str());
  if (!text) {
    DEBUG_OLEDDISPLAY("[OLEDDISPLAY][drawString] Can't allocate char array.\n");
    return 0;
  }

  uint16_t yOffset = 0;
  // If the string should be centered vertically too
  // we need to now how heigh the string is.
  if (textAlignment == TEXT_ALIGN_CENTER_BOTH) {
    uint16_t lb = 0;
    // Find number of linebreaks in text
    for (uint16_t i=0;text[i] != 0; i++) {
      lb += (text[i] == 10);
    }
    // Calculate center
    yOffset = (lb * lineHeight) / 2;
  }

  uint16_t charDrawn = 0;
  uint16_t line = 0;
  char* textPart = strtok(text,"\n");
  while (textPart != NULL) {
    uint16_t length = strlen(textPart);
    charDrawn += drawStringInternal(xMove, yMove - yOffset + (line++) * lineHeight, textPart, length, getStringWidth(textPart, length, true), true);
    textPart = strtok(NULL, "\n");
  }
  free(text);
  return charDrawn;
}

void OLEDDisplay::drawStringf( int16_t x, int16_t y, char* buffer, String format, ... )
{
  va_list myargs;
  va_start(myargs, format);
  vsprintf(buffer, format.c_str(), myargs);
  va_end(myargs);
  drawString( x, y, buffer );
}

uint16_t OLEDDisplay::drawStringMaxWidth(int16_t xMove, int16_t yMove, uint16_t maxLineWidth, const String &strUser) {
  uint16_t firstChar  = pgm_read_byte(fontData + FIRST_CHAR_POS);
  uint16_t lineHeight = pgm_read_byte(fontData + HEIGHT_POS);

  const char* text = strUser.c_str();

  uint16_t length = strlen(text);
  uint16_t lastDrawnPos = 0;
  uint16_t lineNumber = 0;
  uint16_t strWidth = 0;

  uint16_t preferredBreakpoint = 0;
  uint16_t widthAtBreakpoint = 0;
  uint16_t firstLineChars = 0;
  uint16_t drawStringResult = 1; // later tested for 0 == error, so initialize to 1

  for (uint16_t i = 0; i < length; i++) {
    char c = (this->fontTableLookupFunction)(text[i]);
    if (c == 0)
      continue;
    strWidth += pgm_read_byte(fontData + JUMPTABLE_START + (c - firstChar) * JUMPTABLE_BYTES + JUMPTABLE_WIDTH);

    // Always try to break on a space, dash or slash
    if (text[i] == ' ' || text[i]== '-' || text[i] == '/') {
      preferredBreakpoint = i + 1;
      widthAtBreakpoint = strWidth;
    }

    if (strWidth >= maxLineWidth) {
      if (preferredBreakpoint == 0) {
        preferredBreakpoint = i;
        widthAtBreakpoint = strWidth;
      }
      drawStringResult = drawStringInternal(xMove, yMove + (lineNumber++) * lineHeight , &text[lastDrawnPos], preferredBreakpoint - lastDrawnPos, widthAtBreakpoint, true);
      if (firstLineChars == 0)
        firstLineChars = preferredBreakpoint;
      lastDrawnPos = preferredBreakpoint;
      // It is possible that we did not draw all letters to i so we need
      // to account for the width of the chars from `i - preferredBreakpoint`
      // by calculating the width we did not draw yet.
      strWidth = strWidth - widthAtBreakpoint;
      preferredBreakpoint = 0;
      if (drawStringResult == 0) // we are past the display already?
        break;
    }
  }

  // Draw last part if needed
  if (drawStringResult != 0 && lastDrawnPos < length) {
    drawStringResult = drawStringInternal(xMove, yMove + (lineNumber++) * lineHeight , &text[lastDrawnPos], length - lastDrawnPos, getStringWidth(&text[lastDrawnPos], length - lastDrawnPos, true), true);
  }

  if (drawStringResult == 0 || (yMove + lineNumber * lineHeight) >= this->height()) // text did not fit on screen
    return firstLineChars;
  return 0; // everything was drawn
}

uint16_t OLEDDisplay::getStringWidth(const char* text, uint16_t length, bool utf8) {
  uint16_t firstChar        = pgm_read_byte(fontData + FIRST_CHAR_POS);

  uint16_t stringWidth = 0;
  uint16_t maxWidth = 0;

  for (uint16_t i = 0; i < length; i++) {
    char c = text[i];
    if (utf8) {
      c = (this->fontTableLookupFunction)(c);
      if (c == 0)
        continue;
    }
    stringWidth += pgm_read_byte(fontData + JUMPTABLE_START + (c - firstChar) * JUMPTABLE_BYTES + JUMPTABLE_WIDTH);
    if (c == 10) {
      maxWidth = max(maxWidth, stringWidth);
      stringWidth = 0;
    }
  }

  return max(maxWidth, stringWidth);
}

uint16_t OLEDDisplay::getStringWidth(const String &strUser) {
  uint16_t width = getStringWidth(strUser.c_str(), strUser.length());
  return width;
}

void OLEDDisplay::setTextAlignment(OLEDDISPLAY_TEXT_ALIGNMENT textAlignment) {
  this->textAlignment = textAlignment;
}

void OLEDDisplay::setFont(const uint8_t *fontData) {
  this->fontData = fontData;
  // New font, so must recalculate. Whatever was there is gone at next print.
  setLogBuffer();
}

void OLEDDisplay::setFont(const char *fontData) {
  setFont(static_cast<const uint8_t*>(reinterpret_cast<const void*>(fontData)));
}

void OLEDDisplay::displayOn(void) {
  sendCommand(DISPLAYON);
}

void OLEDDisplay::displayOff(void) {
  sendCommand(DISPLAYOFF);
}

void OLEDDisplay::invertDisplay(void) {
  sendCommand(INVERTDISPLAY);
}

void OLEDDisplay::normalDisplay(void) {
  sendCommand(NORMALDISPLAY);
}

void OLEDDisplay::setContrast(uint8_t contrast, uint8_t precharge, uint8_t comdetect) {
  sendCommand(SETPRECHARGE); //0xD9
  sendCommand(precharge); //0xF1 default, to lower the contrast, put 1-1F
  sendCommand(SETCONTRAST);
  sendCommand(contrast); // 0-255
  sendCommand(SETVCOMDETECT); //0xDB, (additionally needed to lower the contrast)
  sendCommand(comdetect);	//0x40 default, to lower the contrast, put 0
  sendCommand(DISPLAYALLON_RESUME);
  sendCommand(DISPLAYON);
}

void OLEDDisplay::setBrightness(uint8_t brightness) {
  uint8_t contrast = brightness;
  if (brightness < 128) {
    // Magic values to get a smooth/ step-free transition
    contrast = brightness * 1.171;
  } else {
    contrast = brightness * 1.171 - 43;
  }

  uint8_t precharge = 241;
  if (brightness == 0) {
    precharge = 0;
  }
  uint8_t comdetect = brightness / 8;

  setContrast(contrast, precharge, comdetect);
}

void OLEDDisplay::resetOrientation() {
  sendCommand(SEGREMAP);
  sendCommand(COMSCANINC);           //Reset screen rotation or mirroring
}

void OLEDDisplay::flipScreenVertically() {
  sendCommand(SEGREMAP | 0x01);
  sendCommand(COMSCANDEC);           //Rotate screen 180 Deg
}

void OLEDDisplay::mirrorScreen() {
  sendCommand(SEGREMAP);
  sendCommand(COMSCANDEC);           //Mirror screen
}

void OLEDDisplay::clear(void) {
  memset(buffer, 0, displayBufferSize);
}

void OLEDDisplay::drawLogBuffer(uint16_t xMove, uint16_t yMove) {
#if !defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_SERIAL)
  Serial.println("[deprecated] Print functionality now handles buffer management automatically. This is a no-op.");
#endif
}

void OLEDDisplay::drawLogBuffer() {
  uint16_t lineHeight = pgm_read_byte(fontData + HEIGHT_POS);
  // Always align left
  setTextAlignment(TEXT_ALIGN_LEFT);

  // State values
  uint16_t length   = 0;
  uint16_t line     = 0;
  uint16_t lastPos  = 0;

  // If the lineHeight and the display height are not cleanly divisible, we need
  // to start off the screen when the buffer has logBufferMaxLines so that the
  // first line, and not the last line, drops off.
  uint16_t shiftUp = (this->logBufferLine == this->logBufferMaxLines) ? (lineHeight - (displayHeight % lineHeight)) % lineHeight : 0;

  for (uint16_t i=0;i<this->logBufferFilled;i++){
    length++;
    // Everytime we have a \n print
    if (this->logBuffer[i] == 10) {
      // Draw string on line `line` from lastPos to length
      // Passing 0 as the lenght because we are in TEXT_ALIGN_LEFT
      drawStringInternal(0, 0 - shiftUp + (line++) * lineHeight, &this->logBuffer[lastPos], length, 0, false);
      // Remember last pos
      lastPos = i;
      // Reset length
      length = 0;
    }
  }
  // Draw the remaining string
  if (length > 0) {
    drawStringInternal(0, 0 - shiftUp + line * lineHeight, &this->logBuffer[lastPos], length, 0, false);
  }
}

uint16_t OLEDDisplay::getWidth(void) {
  return displayWidth;
}

uint16_t OLEDDisplay::getHeight(void) {
  return displayHeight;
}

void OLEDDisplay::cls() {
  clear();
  this->logBufferFilled = 0;
  this->logBufferLine = 0;
  display();
}

bool OLEDDisplay::setLogBuffer(uint16_t lines, uint16_t chars) {
#if !defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_SERIAL)
  Serial.println("[deprecated] Print functionality now handles buffer management automatically. This is a no-op.");
#endif
  return true;
}

bool OLEDDisplay::setLogBuffer(){
  // don't know how big we need it without a font set.
  if (!fontData)
		return false;
  
  // we're always starting over
  if (logBuffer != NULL)
    free(logBuffer);

  // figure out how big it needs to be
  uint8_t textHeight = pgm_read_byte(fontData + HEIGHT_POS);
  if (!textHeight)
    return false;  // Prevent division by zero crashes
  uint16_t lines =  this->displayHeight / textHeight + (this->displayHeight % textHeight ? 1 : 0);
  uint16_t chars =   5 * (this->displayWidth / textHeight);
  uint16_t size = lines * (chars + 1);  // +1 is for \n

  // Something weird must have happened
  if (size == 0) 
    return false;

  // All good, initialize logBuffer
  this->logBufferLine     = 0;      // Lines printed
  this->logBufferFilled   = 0;      // Nothing stored yet
  this->logBufferMaxLines = lines;  // Lines max printable
  this->logBufferLineLen  = chars;  // Chars per line
  this->logBufferSize     = size;   // Total number of characters the buffer can hold
  this->logBuffer         = (char *) malloc(size * sizeof(uint8_t));
  if(!this->logBuffer) {
    DEBUG_OLEDDISPLAY("[OLEDDISPLAY][setLogBuffer] Not enough memory to create log buffer\n");
    return false;
  }

  return true;
}

size_t OLEDDisplay::write(uint8_t c) {
  if (!fontData)
		return 1;
    
  // Create a logBuffer if there isn't one
	if (!logBufferSize) {
    // Give up if we can't create a logBuffer somehow
		if (!setLogBuffer())
      return 1;
	}

  // Don't waste space on \r\n line endings, dropping \r
  if (c == 13) return 1;

  // convert UTF-8 character to font table index
  c = (this->fontTableLookupFunction)(c);
  // drop unknown character
  if (c == 0) return 1;

  bool maxLineReached = this->logBufferLine >= this->logBufferMaxLines;
  bool bufferFull = this->logBufferFilled >= this->logBufferSize;

  // Can we write to the buffer? If not, make space.
  if (bufferFull || maxLineReached) {
    // See if we can chop off the first line
    uint16_t firstLineEnd = 0;
    for (uint16_t i = 0; i < this->logBufferFilled; i++) {
      if (this->logBuffer[i] == 10){
        // Include last char too
        firstLineEnd = i + 1;
        // Calculate the new logBufferFilled value
        this->logBufferFilled = logBufferFilled - firstLineEn
Download .txt
gitextract_do6gekij/

├── .editorconfig
├── .github/
│   ├── ISSUE_TEMPLATE/
│   │   ├── bug_report.md
│   │   └── support-request.md
│   ├── stale.yml
│   └── workflows/
│       └── main.yml
├── .gitignore
├── CMakeLists.txt
├── CONTRIBUTING.md
├── README.md
├── README_GEOMETRY_64_48.md
├── UPGRADE-3.0.md
├── UPGRADE-4.0.md
├── component.mk
├── examples/
│   ├── SSD1306ClockDemo/
│   │   ├── SSD1306ClockDemo.ino
│   │   └── images.h
│   ├── SSD1306DrawingDemo/
│   │   └── SSD1306DrawingDemo.ino
│   ├── SSD1306FontTryout/
│   │   ├── Dialog_plain_6.h
│   │   ├── Dialog_plain_7.h
│   │   ├── Dialog_plain_8.h
│   │   └── SSD1306FontTryout.ino
│   ├── SSD1306OTADemo/
│   │   └── SSD1306OTADemo.ino
│   ├── SSD1306ScrollVerticalDemo/
│   │   └── SSD1306ScrollVerticalDemo.ino
│   ├── SSD1306SimpleDemo/
│   │   ├── SSD1306SimpleDemo.ino
│   │   └── images.h
│   ├── SSD1306TwoScreenDemo/
│   │   ├── SSD1306TwoScreenDemo.ino
│   │   └── images.h
│   └── SSD1306UiDemo/
│       ├── SSD1306UiDemo.ino
│       └── images.h
├── keywords.txt
├── library.json
├── library.properties
├── license
├── platformio.ini
├── resources/
│   └── glyphEditor.html
└── src/
    ├── OLEDDisplay.cpp
    ├── OLEDDisplay.h
    ├── OLEDDisplayFonts.h
    ├── OLEDDisplayUi.cpp
    ├── OLEDDisplayUi.h
    ├── SH1106.h
    ├── SH1106Brzo.h
    ├── SH1106Spi.h
    ├── SH1106Wire.h
    ├── SSD1306.h
    ├── SSD1306Brzo.h
    ├── SSD1306I2C.h
    ├── SSD1306Spi.h
    └── SSD1306Wire.h
Download .txt
SYMBOL INDEX (54 symbols across 13 files)

FILE: src/OLEDDisplay.cpp
  function OLEDDISPLAY_COLOR (line 133) | OLEDDISPLAY_COLOR OLEDDisplay::getColor() {
  function DefaultFontTableLookup (line 1199) | char DefaultFontTableLookup(const uint8_t ch) {

FILE: src/OLEDDisplay.h
  function class (line 48) | class String {
  function length (line 51) | int length() { return strlen(_str); }
  type OLEDDISPLAY_COLOR (line 124) | enum OLEDDISPLAY_COLOR {
  type OLEDDISPLAY_TEXT_ALIGNMENT (line 130) | enum OLEDDISPLAY_TEXT_ALIGNMENT {
  type OLEDDISPLAY_GEOMETRY (line 138) | enum OLEDDISPLAY_GEOMETRY {
  type HW_I2C (line 146) | enum HW_I2C {
  function class (line 158) | class OLEDDisplay : public Stream {

FILE: src/OLEDDisplayUi.cpp
  function LoadingDrawDefault (line 34) | void LoadingDrawDefault(OLEDDisplay *display, LoadingStage* stage, uint8...
  function OLEDDisplayUiState (line 224) | OLEDDisplayUiState* OLEDDisplayUi::getUiState(){

FILE: src/OLEDDisplayUi.h
  type AnimationDirection (line 51) | enum AnimationDirection {
  type IndicatorPosition (line 58) | enum IndicatorPosition {
  type IndicatorDirection (line 65) | enum IndicatorDirection {
  type FrameState (line 70) | enum FrameState {
  type OLEDDisplayUiState (line 86) | struct OLEDDisplayUiState {
  type LoadingStage (line 104) | struct LoadingStage {
  function class (line 113) | class OLEDDisplayUi {

FILE: src/SH1106.h
  type SH1106Wire (line 36) | typedef SH1106Wire SH1106;

FILE: src/SH1106Brzo.h
  function class (line 43) | class SH1106Brzo : public OLEDDisplay {
  function connect (line 58) | bool connect(){
  function display (line 63) | void display(void) {
  function sendCommand (line 133) | inline void sendCommand(uint8_t com) __attribute__((always_inline)){

FILE: src/SH1106Spi.h
  function class (line 37) | class SH1106Spi : public OLEDDisplay {
  function connect (line 53) | bool connect(){
  function display (line 72) | void display(void) {
  function set_CS (line 141) | inline void set_CS(bool level) {
  function sendCommand (line 146) | inline void sendCommand(uint8_t com) __attribute__((always_inline)){

FILE: src/SH1106Wire.h
  function class (line 49) | class SH1106Wire : public OLEDDisplay {
  function connect (line 88) | bool connect() {
  function display (line 103) | void display(void) {
  function setI2cAutoInit (line 184) | void setI2cAutoInit(bool doI2cAutoInit) {
  function sendCommand (line 192) | inline void sendCommand(uint8_t command) __attribute__((always_inline)){
  function initI2cIfNeccesary (line 199) | void initI2cIfNeccesary() {

FILE: src/SSD1306.h
  type SSD1306Wire (line 36) | typedef SSD1306Wire SSD1306;

FILE: src/SSD1306Brzo.h
  function class (line 43) | class SSD1306Brzo : public OLEDDisplay {
  function connect (line 58) | bool connect(){
  function display (line 63) | void display(void) {
  function sendCommand (line 159) | inline void sendCommand(uint8_t com) __attribute__((always_inline)){

FILE: src/SSD1306I2C.h
  function class (line 43) | class SSD1306I2C : public OLEDDisplay {
  function connect (line 54) | bool connect() {
  function display (line 64) | void display(void) {
  function sendCommand (line 137) | inline void sendCommand(uint8_t command) __attribute__((always_inline)) {

FILE: src/SSD1306Spi.h
  function class (line 43) | class SSD1306Spi : public OLEDDisplay {
  function connect (line 59) | bool connect(){
  function display (line 78) | void display(void) {
  function set_CS (line 157) | inline void set_CS(bool level) {
  function sendCommand (line 162) | inline void sendCommand(uint8_t com) __attribute__((always_inline)){

FILE: src/SSD1306Wire.h
  function class (line 49) | class SSD1306Wire : public OLEDDisplay {
  function connect (line 89) | bool connect() {
  function display (line 104) | void display(void) {
  function setI2cAutoInit (line 188) | void setI2cAutoInit(bool doI2cAutoInit) {
  function sendCommand (line 196) | inline void sendCommand(uint8_t command) __attribute__((always_inline)){
  function initI2cIfNeccesary (line 204) | void initI2cIfNeccesary() {
Condensed preview — 48 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (401K chars).
[
  {
    "path": ".editorconfig",
    "chars": 297,
    "preview": "# This file is for unifying the coding style for different editors and IDEs\n# editorconfig.org\n\nroot = true\n\n[*]\nend_of_"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/bug_report.md",
    "chars": 787,
    "preview": "---\nname: Bug report\nabout: Create a report to help us improve\ntitle: ''\nlabels: ''\nassignees: ''\n\n---\n\n**Describe the b"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/support-request.md",
    "chars": 240,
    "preview": "---\nname: Support request\nabout: Describe this issue template's purpose here.\ntitle: ''\nlabels: ''\nassignees: ''\n\n---\n\nW"
  },
  {
    "path": ".github/stale.yml",
    "chars": 684,
    "preview": "# Number of days of inactivity before an issue becomes stale\ndaysUntilStale: 180\n# Number of days of inactivity before a"
  },
  {
    "path": ".github/workflows/main.yml",
    "chars": 1307,
    "preview": "# documentation at https://docs.platformio.org/en/latest/integration/ci/github-actions.html\n\nname: PlatformIO CI\n\non: [p"
  },
  {
    "path": ".gitignore",
    "chars": 13,
    "preview": ".vscode\n.pio\n"
  },
  {
    "path": "CMakeLists.txt",
    "chars": 126,
    "preview": "set(COMPONENT_ADD_INCLUDEDIRS src)\nset(COMPONENT_PRIV_REQUIRES arduino-esp32)\nset(COMPONENT_SRCDIRS src)\nregister_compon"
  },
  {
    "path": "CONTRIBUTING.md",
    "chars": 4949,
    "preview": "# Contributing to ThingPulse OLED SSD1306\n\n:+1::tada: First off, thanks for taking the time to contribute! :tada::+1:\n\nT"
  },
  {
    "path": "README.md",
    "chars": 18985,
    "preview": "# ThingPulse OLED SSD1306 (ESP8266/ESP32/Mbed-OS)\n\n[![PlatformIO Registry](https://badges.registry.platformio.org/packag"
  },
  {
    "path": "README_GEOMETRY_64_48.md",
    "chars": 452,
    "preview": "# GEOMETRY_64_48\n\nThe 64x48 geometry setting are working with the `Wire.h` and `brzo_i2c` libraries.\n\nI've tested it suc"
  },
  {
    "path": "UPGRADE-3.0.md",
    "chars": 4683,
    "preview": "# Upgrade from 2.0 to 3.0\n\nWhile developing version 3.0 we made some breaking changes to the public\nAPI of this library."
  },
  {
    "path": "UPGRADE-4.0.md",
    "chars": 612,
    "preview": "# Upgrade from 3.x to 4.0\n\nThere are changes that breaks compatibility with older versions.\n\n1. You'll have to change da"
  },
  {
    "path": "component.mk",
    "chars": 94,
    "preview": "COMPONENT_ADD_INCLUDEDIRS := src\nCOMPONENT_SRCDIRS := src\nCXXFLAGS += -Wno-ignored-qualifiers\n"
  },
  {
    "path": "examples/SSD1306ClockDemo/SSD1306ClockDemo.ino",
    "chars": 7437,
    "preview": "/**\n   The MIT License (MIT)\n\n   Copyright (c) 2018 by ThingPulse, Daniel Eichhorn\n\n   Permission is hereby granted, fre"
  },
  {
    "path": "examples/SSD1306ClockDemo/images.h",
    "chars": 329,
    "preview": "const uint8_t activeSymbol[] PROGMEM = {\n    B00000000,\n    B00000000,\n    B00011000,\n    B00100100,\n    B01000010,\n    "
  },
  {
    "path": "examples/SSD1306DrawingDemo/SSD1306DrawingDemo.ino",
    "chars": 6639,
    "preview": "/**\n   The MIT License (MIT)\n\n   Copyright (c) 2018 by ThingPulse, Daniel Eichhorn\n   Copyright (c) 2018 by Fabrice Wein"
  },
  {
    "path": "examples/SSD1306FontTryout/Dialog_plain_6.h",
    "chars": 14397,
    "preview": "// Created by http://oleddisplay.squix.ch/ Consider a donation\n// In case of problems make sure that you are using the f"
  },
  {
    "path": "examples/SSD1306FontTryout/Dialog_plain_7.h",
    "chars": 18352,
    "preview": "// Created by http://oleddisplay.squix.ch/ Consider a donation\n// In case of problems make sure that you are using the f"
  },
  {
    "path": "examples/SSD1306FontTryout/Dialog_plain_8.h",
    "chars": 19722,
    "preview": "// Created by http://oleddisplay.squix.ch/ Consider a donation\n// In case of problems make sure that you are using the f"
  },
  {
    "path": "examples/SSD1306FontTryout/SSD1306FontTryout.ino",
    "chars": 4778,
    "preview": "/**\n   The MIT License (MIT)\n\n   Permission is hereby granted, free of charge, to any person obtaining a copy\n   of this"
  },
  {
    "path": "examples/SSD1306OTADemo/SSD1306OTADemo.ino",
    "chars": 4261,
    "preview": "/**\n   The MIT License (MIT)\n\n   Copyright (c) 2018 by ThingPulse, Daniel Eichhorn\n   Copyright (c) 2018 by Fabrice Wein"
  },
  {
    "path": "examples/SSD1306ScrollVerticalDemo/SSD1306ScrollVerticalDemo.ino",
    "chars": 3467,
    "preview": "/**\n   The MIT License (MIT)\n\n   Copyright (c) 2022 by Stefan Seyfried\n\n   Permission is hereby granted, free of charge,"
  },
  {
    "path": "examples/SSD1306SimpleDemo/SSD1306SimpleDemo.ino",
    "chars": 6527,
    "preview": "/**\n   The MIT License (MIT)\n\n   Copyright (c) 2018 by ThingPulse, Daniel Eichhorn\n   Copyright (c) 2018 by Fabrice Wein"
  },
  {
    "path": "examples/SSD1306SimpleDemo/images.h",
    "chars": 1879,
    "preview": "#define WiFi_Logo_width 60\n#define WiFi_Logo_height 36\nconst uint8_t WiFi_Logo_bits[] PROGMEM = {\n  0x00, 0x00, 0x00, 0x"
  },
  {
    "path": "examples/SSD1306TwoScreenDemo/SSD1306TwoScreenDemo.ino",
    "chars": 2819,
    "preview": "/**\n   The MIT License (MIT)\n\n   Copyright (c) 2018 by ThingPulse, Daniel Eichhorn\n\n   Permission is hereby granted, fre"
  },
  {
    "path": "examples/SSD1306TwoScreenDemo/images.h",
    "chars": 1879,
    "preview": "#define WiFi_Logo_width 60\n#define WiFi_Logo_height 36\nconst uint8_t WiFi_Logo_bits[] PROGMEM = {\n  0x00, 0x00, 0x00, 0x"
  },
  {
    "path": "examples/SSD1306UiDemo/SSD1306UiDemo.ino",
    "chars": 6780,
    "preview": "/**\n   The MIT License (MIT)\n\n   Copyright (c) 2018 by ThingPulse, Daniel Eichhorn\n   Copyright (c) 2018 by Fabrice Wein"
  },
  {
    "path": "examples/SSD1306UiDemo/images.h",
    "chars": 2209,
    "preview": "#define WiFi_Logo_width 60\n#define WiFi_Logo_height 36\nconst uint8_t WiFi_Logo_bits[] PROGMEM = {\n  0x00, 0x00, 0x00, 0x"
  },
  {
    "path": "keywords.txt",
    "chars": 2235,
    "preview": "#######################################\n# Syntax Coloring Map List\n#######################################\n\n\n###########"
  },
  {
    "path": "library.json",
    "chars": 718,
    "preview": "{\n  \"name\": \"ESP8266 and ESP32 OLED driver for SSD1306 displays\",\n  \"version\": \"4.6.2\",\n  \"keywords\": \"ssd1306, oled, di"
  },
  {
    "path": "library.properties",
    "chars": 511,
    "preview": "name=ESP8266 and ESP32 OLED driver for SSD1306 displays\nversion=4.6.2\nauthor=ThingPulse, Fabrice Weinberg\nmaintainer=Thi"
  },
  {
    "path": "license",
    "chars": 1158,
    "preview": "The MIT License (MIT)\n\nCopyright (c) 2016 by Daniel Eichhorn\nCopyright (c) 2016 by Fabrice Weinberg\n\nPermission is hereb"
  },
  {
    "path": "platformio.ini",
    "chars": 578,
    "preview": "; PlatformIO Project Configuration File\n;\n;   Build options: build flags, source filter\n;   Upload options: custom uploa"
  },
  {
    "path": "resources/glyphEditor.html",
    "chars": 28031,
    "preview": "<!--The MIT License (MIT)\n\nCopyright (c) 2017 by Xavier Grosjean\n\nBased on work \nCopyright (c) 2016 by Daniel Eichhorn\nC"
  },
  {
    "path": "src/OLEDDisplay.cpp",
    "chars": 34951,
    "preview": "/**\n * The MIT License (MIT)\n *\n * Copyright (c) 2018 by ThingPulse, Daniel Eichhorn\n * Copyright (c) 2018 by Fabrice We"
  },
  {
    "path": "src/OLEDDisplay.h",
    "chars": 12935,
    "preview": "/**\n * The MIT License (MIT)\n *\n * Copyright (c) 2018 by ThingPulse, Daniel Eichhorn\n * Copyright (c) 2018 by Fabrice We"
  },
  {
    "path": "src/OLEDDisplayFonts.h",
    "chars": 105873,
    "preview": "#ifndef OLEDDISPLAYFONTS_h\n#define OLEDDISPLAYFONTS_h\n\n#ifdef __MBED__\n#define PROGMEM\n#endif\n\nconst uint8_t ArialMT_Pla"
  },
  {
    "path": "src/OLEDDisplayUi.cpp",
    "chars": 15215,
    "preview": "/**\n * The MIT License (MIT)\n *\n * Copyright (c) 2018 by ThingPulse, Daniel Eichhorn\n * Copyright (c) 2018 by Fabrice We"
  },
  {
    "path": "src/OLEDDisplayUi.h",
    "chars": 8033,
    "preview": "/**\n * The MIT License (MIT)\n *\n * Copyright (c) 2018 by ThingPulse, Daniel Eichhorn\n * Copyright (c) 2018 by Fabrice We"
  },
  {
    "path": "src/SH1106.h",
    "chars": 1537,
    "preview": "/**\n * The MIT License (MIT)\n *\n * Copyright (c) 2018 by ThingPulse, Daniel Eichhorn\n * Copyright (c) 2018 by Fabrice We"
  },
  {
    "path": "src/SH1106Brzo.h",
    "chars": 4350,
    "preview": "/**\n * The MIT License (MIT)\n *\n * Copyright (c) 2018 by ThingPulse, Daniel Eichhorn\n * Copyright (c) 2018 by Fabrice We"
  },
  {
    "path": "src/SH1106Spi.h",
    "chars": 4682,
    "preview": "/**\n * The MIT License (MIT)\n *\n * Copyright (c) 2018 by ThingPulse, Daniel Eichhorn\n * Copyright (c) 2018 by Fabrice We"
  },
  {
    "path": "src/SH1106Wire.h",
    "chars": 7227,
    "preview": "/**\n * The MIT License (MIT)\n *\n * Copyright (c) 2018 by ThingPulse, Daniel Eichhorn\n * Copyright (c) 2018 by Fabrice We"
  },
  {
    "path": "src/SSD1306.h",
    "chars": 1555,
    "preview": "/**\n * The MIT License (MIT)\n *\n * Copyright (c) 2018 by ThingPulse, Daniel Eichhorn\n * Copyright (c) 2018 by Fabrice We"
  },
  {
    "path": "src/SSD1306Brzo.h",
    "chars": 5039,
    "preview": "/**\n * The MIT License (MIT)\n *\n * Copyright (c) 2018 by ThingPulse, Daniel Eichhorn\n * Copyright (c) 2018 by Fabrice We"
  },
  {
    "path": "src/SSD1306I2C.h",
    "chars": 4684,
    "preview": "/**\n * The MIT License (MIT)\n *\n * Copyright (c) 2019 by Helmut Tschemernjak - www.radioshuttle.de\n *\n * Permission is h"
  },
  {
    "path": "src/SSD1306Spi.h",
    "chars": 4935,
    "preview": "/**\n * The MIT License (MIT)\n *\n * Copyright (c) 2018 by ThingPulse, Daniel Eichhorn\n * Copyright (c) 2018 by Fabrice We"
  },
  {
    "path": "src/SSD1306Wire.h",
    "chars": 7226,
    "preview": "/**\n * The MIT License (MIT)\n *\n * Copyright (c) 2018 by ThingPulse, Daniel Eichhorn\n * Copyright (c) 2018 by Fabrice We"
  }
]

About this extraction

This page contains the full source code of the squix78/esp8266-oled-ssd1306 GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 48 files (377.1 KB), approximately 191.5k tokens, and a symbol index with 54 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!