dd

Dependencies:   Final HCSR04 TB6612FNG

Files at this revision

API Documentation at this revision

Comitter:
eunmango
Date:
Sun Jun 16 04:44:35 2019 +0000
Parent:
96:ec3a2da01f40
Commit message:
t

Changed in this revision

HCSR04.lib Show annotated file Show diff for this revision Revisions of this file
IRremote.lib Show annotated file Show diff for this revision Revisions of this file
TB6612FNG.lib Show annotated file Show diff for this revision Revisions of this file
main.cpp Show annotated file Show diff for this revision Revisions of this file
oled/Adafruit_GFX.cpp Show annotated file Show diff for this revision Revisions of this file
oled/Adafruit_GFX.h Show annotated file Show diff for this revision Revisions of this file
oled/FreeSans9pt7b.h Show annotated file Show diff for this revision Revisions of this file
oled/SSD1306-Library.cpp Show annotated file Show diff for this revision Revisions of this file
oled/SSD1306-Library.h Show annotated file Show diff for this revision Revisions of this file
oled/gfxfont.h Show annotated file Show diff for this revision Revisions of this file
oled/glcdfont.c Show annotated file Show diff for this revision Revisions of this file
diff -r ec3a2da01f40 -r b483e656bd14 HCSR04.lib
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/HCSR04.lib	Sun Jun 16 04:44:35 2019 +0000
@@ -0,0 +1,1 @@
+https://os.mbed.com/teams/Embedded-Class-Final-Project1/code/HCSR04/#b3401c36a10b
diff -r ec3a2da01f40 -r b483e656bd14 IRremote.lib
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/IRremote.lib	Sun Jun 16 04:44:35 2019 +0000
@@ -0,0 +1,1 @@
+https://os.mbed.com/teams/Embedded-Class-Final-Project/code/Final/#0650578366fd
diff -r ec3a2da01f40 -r b483e656bd14 TB6612FNG.lib
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/TB6612FNG.lib	Sun Jun 16 04:44:35 2019 +0000
@@ -0,0 +1,1 @@
+https://os.mbed.com/users/Pinski1/code/TB6612FNG/#7f18197d1210
diff -r ec3a2da01f40 -r b483e656bd14 main.cpp
--- a/main.cpp	Fri May 31 13:00:04 2019 +0100
+++ b/main.cpp	Sun Jun 16 04:44:35 2019 +0000
@@ -1,32 +1,432 @@
-/* mbed Microcontroller Library
- * Copyright (c) 2018 ARM Limited
- * SPDX-License-Identifier: Apache-2.0
- */
+#include "mbed.h"
+#include <iostream>
+#include "HCSR04.h"
+#include <list>
+#include <string.h>
+#include <IRremote.h>
+#include "TB6612FNG.h"
+//#define PCF8574_ADDR     (0x40) 
+#define LEFT 127
+#define RIGHT 191
+#define NUMSENSORS 5
+#define MAX 1023
+#define MIN 0
+#define TRU 1
+#define FALS 0
+#define MaxSpeed 255// max speed of the robot
+#define BaseSpeed 155 
+#define speedt 180
+
+#include "SSD1306-Library.h"
+#include "FreeSans9pt7b.h"
+#include <time.h>
+#include <math.h>
+
+#define KEY2 0xFF18E7                 //Key:2 
+#define KEY8 0xFF52AD                 //Key:8 
+#define KEY4 0xFF08F7                 //Key:4 
+#define KEY6 0xFF5AA5                 //Key:6 
+#define KEY1 0xFF0CF3                 //Key:1 
+#define KEY3 0xFF5EA1                 //Key:3 
+#define KEY5 0xFF1CE3                 //Key:5
+
+
+//I2C i2c(I2C_SDA, I2C_SCL);  //D15,D14
+SPI spi(D11, D12, D13);
+DigitalOut cs(D10,1);
+Serial pc(PA_2, PA_3, 115200); //D1 D0
+IRrecv irrecv(D4);
+
+
+int mode=1;
+int index=0;
+int rx_buffer[10];
+char arr[16];
+volatile int flag = 0;
+float interval=0.1; //100ms
+decode_results result;
+
+
+
+/////////sensors////////////
+
+int temp=0;
+int calibratedMin[NUMSENSORS];
+int calibratedMax[NUMSENSORS];
+unsigned int sensor_values[NUMSENSORS];
+int in_line[NUMSENSORS];
+int ultra_flag=0;
+float position;
+
+/////////sensors////////////
+
+/////////Ultrasonic////////////
+Ultrasonic ultra(D3, D2);
+int ultra_result=10;
+/////////Ultrasonic////////////
+
+
+//////////motor////////////
+PwmOut      motor_pwmA(PB_10); //D6
+PwmOut      motor_pwmb(PB_4);  // D5
+AnalogIn rightMotor2(A0);
+AnalogIn rightMotor1(A1);
+AnalogIn leftMotor2(A3);
+AnalogIn leftMotor1(A2);
+
+TB6612FNG leftmotor(PB_10, A1, A0);
+TB6612FNG rightmotor(PB_4, A2, A3);
+float last_proportional;
+float integral;
+float kp = 0.5;
+float kd = 0.1;
+int lastError;
+//////////motor////////////
+
+void IRForward(void)
+{
+    leftmotor.setSpeed(0.1);
+    rightmotor.setSpeed(0.1);
+
+}
+
+void ultraLeft(){
+    leftmotor.setSpeed(-0.13);
+    rightmotor.setSpeed(0.15);
+}
+
+void left(void)
+{
+    leftmotor.setSpeed(0.03);
+    rightmotor.setSpeed(0.15);
+}
+
+
+void right(void)
+{
+    leftmotor.setSpeed(0.15);
+    rightmotor.setSpeed(0.03);
+}
+
+void stop(void)
+{
+    leftmotor.setSpeed(0);
+    rightmotor.setSpeed(0);
+}
+
+void CalibrationMotor(void)
+{
+    leftmotor.setSpeed(0.15);
+    rightmotor.setSpeed(-0.15);
+}
+
+void backward(void)
+{
+   leftmotor.setSpeed(-0.1);
+   rightmotor.setSpeed(-0.1);
+}
+
 
-#include "mbed.h"
-#include "stats_report.h"
+//bool pcf8574_write(uint8_t data){
+//    return i2c.write(PCF8574_ADDR, (char*) &data, 1, 0) == 0;
+//}
+//
+//bool pcf8574_read(uint8_t* data){
+//    return i2c.read(PCF8574_ADDR, (char*) data, 1, 0) == 0;
+//}
+//
+//int pcf8574_test(uint8_t value){
+//    
+//    int ret;
+//    uint8_t data=0;
+//    
+//    ret = pcf8574_write(value);
+//    if(!ret) return -1;
+//    
+//    ret = pcf8574_read(&data);
+//    if(!ret) return -2;
+//    
+//    return data;
+//}
+//
+//void detected(void)
+//{
+//    pcf8574_test(0xff);
+//    while(pcf8574_test(0xff)<255) pcf8574_test(0x00);
+//}
+
+int state=0; //0:forward / 1:left / 2:right
+int cnt=0;
+ int period_us;
+    int beat_ms;
 
-DigitalOut led1(LED1);
+void TRSensors(void) {
+    
+    for(int i=0; i< NUMSENSORS ; i++) {
+            calibratedMin[i]= MAX;
+            calibratedMax[i] = MIN;
+    }
+        
+}
+
+void set_TLC1543 (void) {
+   
+   int value;
+   for(int i=0; i<6 ; i++){
+    cs=0;
+    wait_us(2);
+    value=spi.write(i<<12);
+    cs=1;
+    wait_us(21);
+    cs=0;
+    wait_us(2);
+    value=spi.write(i<<12);
+    //pc.printf("%d th : 0x%X\r\n", i, value);
+    cs=1;
+    wait_us(21);
+    sensor_values[i]=value;
+    }   
+}
+
+void calibrate(void){
+    int i;
+
+    unsigned int max_sensor_values[NUMSENSORS];
+    unsigned int min_sensor_values[NUMSENSORS];   
+    
+    int j;
+    for(j=0; j <10 ; j++){
+         set_TLC1543();
+         for(i=0; i<NUMSENSORS; i++){
+         if(j==0 || max_sensor_values[i] < sensor_values[i]) max_sensor_values[i] = sensor_values[i];
+         if(j==0 || min_sensor_values[i] > sensor_values[i]) min_sensor_values[i] = sensor_values[i];
+         }
+    }
+    
+    for(i=0; i<NUMSENSORS; i++){
+        if(min_sensor_values[i] > calibratedMax[i]) calibratedMax[i] = min_sensor_values[i];
+        if(max_sensor_values[i] < calibratedMin[i]) calibratedMin[i] = max_sensor_values[i];
+    }
+
+}
 
-#define SLEEP_TIME                  500 // (msec)
-#define PRINT_AFTER_N_LOOPS         20
+void readCalibrated(){
+    int i;
+    set_TLC1543();
+    for(i=0; i<NUMSENSORS ; i++){
+        //unsigned int calmin, calmax;
+        unsigned int denominator;
+        denominator = calibratedMax[i] - calibratedMin[i];
+        signed int x =0;
+        if(denominator !=0) {
+            x = (   (     (signed long)sensor_values[i]  ) -calibratedMin[i]) * 1000 / denominator;    
+        }
+        if(x<0) x=0;
+        else if(x>1000) x= 1000;
+        else sensor_values[i] = x;
+    }    
+}
 
-// main() runs in its own thread in the OS
+int readLine() {
+    unsigned char i, on_line =0;
+    unsigned long avg;
+    unsigned int sum;
+    static int last_value=0;
+    
+    readCalibrated();
+    avg =0; sum =0;
+    for(i=0; i< NUMSENSORS; i++){
+        int value = sensor_values[i];
+        value = 1000-value;
+        sensor_values[i]=value;
+        in_line[i]=FALS;
+        if(value > 300) {
+            on_line =1;
+            in_line[i]=TRU;
+        }  
+        //if(value > calibratedMin[i]) on_line=1;
+        if(value > 50){
+        avg += (long)(value)*(i*1000);
+        sum += value;    
+        }         
+    }
+    
+    if(!on_line){
+        if(last_value < (NUMSENSORS-1)*1000/2) return 0;
+        else return ( NUMSENSORS-1 ) * 1000;   
+    }
+   
+   last_value = avg/sum;
+   
+   return last_value;
+            
+}
+
+/****************************************************************
+before running, set up tlc1543, calibrate **********************/
+void settlc1543(){
+    cs =1;
+    spi.format(16,0);
+    spi.frequency(2000000);
+    pc.printf("test\r\n");
+    //pc.attach(callback(&rx_cb));
+    
+    TRSensors();
+    for(int i=0; i<10; i++) {
+        calibrate();
+        wait(0.4);
+    }
+//    pc.printf("calibrate done\r\n");
+    for(int i=0; i<NUMSENSORS; i++) {
+//        pc.printf("Calibration Min: %d Max: %d\r\n", calibratedMin[i], calibratedMax[i] );
+    }
+}
+
+
+void rx_cb(void) {
+  
+    int ch;
+    ch = pc.getc();
+    rx_buffer[index]=ch;
+    index++;
+    pc.putc(ch); 
+   if(ch==0x0D) {
+    pc.putc(0x0A);
+    flag=1;
+    index=0;
+    }
+
+    
+}
+
+
 int main()
 {
-    SystemReport sys_state( SLEEP_TIME * PRINT_AFTER_N_LOOPS /* Loop delay time in ms */);
+    clock_t t;
+    int f;
+    char displaySentence[40] = "Time is ";
+    char time[20];
+    irrecv.enableIRIn();
+//    mu.startUpdates();//start mesuring the distance
+    int data;
+    
+    SSD1306 display = SSD1306();
+    
+    while(1){
+            
+            if(irrecv.decode(&result)){
+            pc.printf("%X\r\n",result.value);
+            irrecv.resume();
+            
+            if(result.value == KEY1){       // 1
+                break;
+            }
+            if(result.value == KEY2){       // 2
+               IRForward();
+            }            
+            if(result.value == KEY3){       // 3
+                CalibrationMotor();
+                settlc1543();
+                
+            }
+            if(result.value == KEY6){       // 6
+               right();
 
-    int count = 0;
-    while (true) {
-        // Blink LED and wait 0.5 seconds
-        led1 = !led1;
-        wait_ms(SLEEP_TIME);
+            }
+            if(result.value == KEY4){       // 4
+               left();
+            }
+            if(result.value == KEY8 ){       // 8
+                backward();
+            }
+            if(result.value == KEY5){       // 5
+               stop();
+            }
+        }
+        
+    }
+
+
+
+    t=clock();
+    pc.printf("Hello PCF8574\n");
+    while (1) {
+
+        ultra_result = ultra.distance();
+        if(ultra_result > 0 && ultra_result < 14) {
+             if(in_line[0]==TRU && in_line[1]==TRU ){
+                stop(); 
+                mode = 2;
+                }
+
+            }
+
 
-        if ((0 == count) || (PRINT_AFTER_N_LOOPS == count)) {
-            // Following the main thread wait, report on the current system status
-            sys_state.report_state();
-            count = 0;
-        }
-        ++count;
+        if(mode == 1){
+            pc.printf("enter\r\n");
+            position = (float)readLine();
+            pc.printf("position: %f\r\n", position);
+            float proportional =(float)(position-2000.0); //e(t)
+            float derivative = (float)(proportional - last_proportional);
+            integral += proportional;
+            last_proportional = proportional;//
+            //pid 15/60000/2 - 85%
+            float power_difference = proportional/16.0+ (float)integral/
+            60000.0+ derivative*2.0;  //integral 변수 커지고 작아지는 값 확인하
+            pc.printf("proportional : %f integral %f derivative : %f \r\n", proportional, integral, derivative);
+            const int maximum = 255;
+            const int base = 155;
+            pc.printf("power_difference is %f\r\n" , power_difference);
+            if(power_difference > base ) power_difference = base;
+            if(power_difference < -base) power_difference = -base;
+            
+            
+        
+            if(power_difference < 0){ //오른쪽으로 빠
+    //            rightmotor.setSpeed((float)(base + power_difference) / (float)maximum);
+    //            leftmotor.setSpeed((float)base-power_difference/(float)maximum);    
+                pc.printf("right    : left %f, right %f \r\n",(float)(base+power_difference) / (float)maximum , (float)(base) / (float)maximum );
+                rightmotor.setSpeed((float)(base) / (float)maximum);
+                leftmotor.setSpeed((float)(base+power_difference) / (float)maximum );
+            } else{// 왼//쪽으로 빠짐.
+    //            rightmotor.setSpeed((float)(base + power_difference) / (float)maximum);
+    //            leftmotor.setSpeed((float)base-power_difference/(float)maximum); 
+                pc.printf("left    : left %f, right %f \r\n",(float)(base) / (float)maximum , (float)(base -power_difference) / (float)maximum );
+                    leftmotor.setSpeed((float)(base) / (float)maximum);
+                    rightmotor.setSpeed((float)(base -power_difference) / (float)maximum);
+                    
+                }
+                
+                if(in_line[0]&&in_line[1]&&in_line[2]&&in_line[3]&&in_line[4]){
+                    leftmotor.setSpeed(0);
+                    rightmotor.setSpeed(0);
+                    pc.printf("stop\r\n");
+                    //시간 모니터에 출력.
+                    break;
+                }         
+            }
+
+            if(mode == 2){
+                ultra_result = ultra.distance(); 
+                                  
+                for(int i=0; i<50; i++){
+                    data = readLine();
+                    if(in_line[2]==TRU && in_line[1]==FALS && in_line[3]==FALS && in_line[0]==FALS && in_line[4]==FALS) 
+                    {
+                        mode=1;
+                        break;
+                    }
+                    ultraLeft();
+                }
+            }
     }
-}
+                display.begin(true);
+                display.setTextSize(1);
+                display.setTextColor(WHITE);
+                display.setCursor(0,0);
+                t=clock()-t;
+                sprintf(time, "%f ms", (float)t*10); 
+                strcat(displaySentence, time);
+                display.println(displaySentence);
+                display.display();
+}
\ No newline at end of file
diff -r ec3a2da01f40 -r b483e656bd14 oled/Adafruit_GFX.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/oled/Adafruit_GFX.cpp	Sun Jun 16 04:44:35 2019 +0000
@@ -0,0 +1,752 @@
+/*
+This is the core graphics library for all our displays, providing a common
+set of graphics primitives (points, lines, circles, etc.).  It needs to be
+paired with a hardware-specific library for each display device we carry
+(to handle the lower-level functions).
+
+Adafruit invests time and resources providing this open source code, please
+support Adafruit & open-source hardware by purchasing products from Adafruit!
+
+Copyright (c) 2013 Adafruit Industries.  All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+- Redistributions of source code must retain the above copyright notice,
+  this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright notice,
+  this list of conditions and the following disclaimer in the documentation
+  and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "Adafruit_GFX.h"
+#include "glcdfont.c"
+
+// Many (but maybe not all) non-AVR board installs define macros
+// for compatibility with existing PROGMEM-reading AVR code.
+// Do our own checks and defines here for good measure...
+
+#ifndef pgm_read_byte
+ #define pgm_read_byte(addr) (*(const unsigned char *)(addr))
+#endif
+#ifndef pgm_read_word
+ #define pgm_read_word(addr) (*(const unsigned short *)(addr))
+#endif
+#ifndef pgm_read_dword
+ #define pgm_read_dword(addr) (*(const unsigned long *)(addr))
+#endif
+
+// Pointers are a peculiar case...typically 16-bit on AVR boards,
+// 32 bits elsewhere.  Try to accommodate both...
+
+#if !defined(__INT_MAX__) || (__INT_MAX__ > 0xFFFF)
+ #define pgm_read_pointer(addr) ((void *)pgm_read_dword(addr))
+#else
+ #define pgm_read_pointer(addr) ((void *)pgm_read_word(addr))
+#endif
+
+#ifndef min
+#define min(a,b) (((a) < (b)) ? (a) : (b))
+#endif
+
+#ifndef _swap_int16_t
+#define _swap_int16_t(a, b) { int16_t t = a; a = b; b = t; }
+#endif
+
+Adafruit_GFX::Adafruit_GFX(int16_t w, int16_t h):
+  WIDTH(w), HEIGHT(h)
+{
+  _width    = WIDTH;
+  _height   = HEIGHT;
+  rotation  = 0;
+  cursor_y  = cursor_x    = 0;
+  textsize  = 1;
+  textcolor = textbgcolor = 0xFFFF;
+  wrap      = true;
+  gfxFont   = NULL;
+}
+
+// Draw a circle outline
+void Adafruit_GFX::drawCircle(int16_t x0, int16_t y0, int16_t r,
+ uint16_t color) {
+  int16_t f = 1 - r;
+  int16_t ddF_x = 1;
+  int16_t ddF_y = -2 * r;
+  int16_t x = 0;
+  int16_t y = r;
+
+  drawPixel(x0  , y0+r, color);
+  drawPixel(x0  , y0-r, color);
+  drawPixel(x0+r, y0  , color);
+  drawPixel(x0-r, y0  , color);
+
+  while (x<y) {
+    if (f >= 0) {
+      y--;
+      ddF_y += 2;
+      f += ddF_y;
+    }
+    x++;
+    ddF_x += 2;
+    f += ddF_x;
+
+    drawPixel(x0 + x, y0 + y, color);
+    drawPixel(x0 - x, y0 + y, color);
+    drawPixel(x0 + x, y0 - y, color);
+    drawPixel(x0 - x, y0 - y, color);
+    drawPixel(x0 + y, y0 + x, color);
+    drawPixel(x0 - y, y0 + x, color);
+    drawPixel(x0 + y, y0 - x, color);
+    drawPixel(x0 - y, y0 - x, color);
+  }
+}
+
+void Adafruit_GFX::drawCircleHelper( int16_t x0, int16_t y0,
+ int16_t r, uint8_t cornername, uint16_t color) {
+  int16_t f     = 1 - r;
+  int16_t ddF_x = 1;
+  int16_t ddF_y = -2 * r;
+  int16_t x     = 0;
+  int16_t y     = r;
+
+  while (x<y) {
+    if (f >= 0) {
+      y--;
+      ddF_y += 2;
+      f     += ddF_y;
+    }
+    x++;
+    ddF_x += 2;
+    f     += ddF_x;
+    if (cornername & 0x4) {
+      drawPixel(x0 + x, y0 + y, color);
+      drawPixel(x0 + y, y0 + x, color);
+    }
+    if (cornername & 0x2) {
+      drawPixel(x0 + x, y0 - y, color);
+      drawPixel(x0 + y, y0 - x, color);
+    }
+    if (cornername & 0x8) {
+      drawPixel(x0 - y, y0 + x, color);
+      drawPixel(x0 - x, y0 + y, color);
+    }
+    if (cornername & 0x1) {
+      drawPixel(x0 - y, y0 - x, color);
+      drawPixel(x0 - x, y0 - y, color);
+    }
+  }
+}
+
+void Adafruit_GFX::fillCircle(int16_t x0, int16_t y0, int16_t r,  uint16_t color) {
+  drawFastVLine(x0, y0-r, 2*r+1, color);
+  fillCircleHelper(x0, y0, r, 3, 0, color);
+}
+
+// Used to do circles and roundrects
+void Adafruit_GFX::fillCircleHelper(int16_t x0, int16_t y0, int16_t r,
+ uint8_t cornername, int16_t delta, uint16_t color) {
+
+  int16_t f     = 1 - r;
+  int16_t ddF_x = 1;
+  int16_t ddF_y = -2 * r;
+  int16_t x     = 0;
+  int16_t y     = r;
+
+  while (x<y) {
+    if (f >= 0) {
+      y--;
+      ddF_y += 2;
+      f     += ddF_y;
+    }
+    x++;
+    ddF_x += 2;
+    f     += ddF_x;
+
+    if (cornername & 0x1) {
+      drawFastVLine(x0+x, y0-y, 2*y+1+delta, color);
+      drawFastVLine(x0+y, y0-x, 2*x+1+delta, color);
+    }
+    if (cornername & 0x2) {
+      drawFastVLine(x0-x, y0-y, 2*y+1+delta, color);
+      drawFastVLine(x0-y, y0-x, 2*x+1+delta, color);
+    }
+  }
+}
+
+// Bresenham's algorithm - thx wikpedia
+void Adafruit_GFX::drawLine(int16_t x0, int16_t y0, int16_t x1, int16_t y1,
+ uint16_t color) {
+  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) {
+      drawPixel(y0, x0, color);
+    } else {
+      drawPixel(x0, y0, color);
+    }
+    err -= dy;
+    if (err < 0) {
+      y0 += ystep;
+      err += dx;
+    }
+  }
+}
+
+// Draw a rectangle
+void Adafruit_GFX::drawRect(int16_t x, int16_t y, int16_t w, int16_t h,
+ uint16_t color) {
+  drawFastHLine(x, y, w, color);
+  drawFastHLine(x, y+h-1, w, color);
+  drawFastVLine(x, y, h, color);
+  drawFastVLine(x+w-1, y, h, color);
+}
+
+void Adafruit_GFX::drawFastVLine(int16_t x, int16_t y,
+ int16_t h, uint16_t color) {
+  // Update in subclasses if desired!
+  drawLine(x, y, x, y+h-1, color);
+}
+
+void Adafruit_GFX::drawFastHLine(int16_t x, int16_t y,
+ int16_t w, uint16_t color) {
+  // Update in subclasses if desired!
+  drawLine(x, y, x+w-1, y, color);
+}
+
+void Adafruit_GFX::fillRect(int16_t x, int16_t y, int16_t w, int16_t h,
+ uint16_t color) {
+  // Update in subclasses if desired!
+  for (int16_t i=x; i<x+w; i++) {
+    drawFastVLine(i, y, h, color);
+  }
+}
+
+void Adafruit_GFX::fillScreen(uint16_t color) {
+  fillRect(0, 0, _width, _height, color);
+}
+
+// Draw a rounded rectangle
+void Adafruit_GFX::drawRoundRect(int16_t x, int16_t y, int16_t w,
+ int16_t h, int16_t r, uint16_t color) {
+  // smarter version
+  drawFastHLine(x+r  , y    , w-2*r, color); // Top
+  drawFastHLine(x+r  , y+h-1, w-2*r, color); // Bottom
+  drawFastVLine(x    , y+r  , h-2*r, color); // Left
+  drawFastVLine(x+w-1, y+r  , h-2*r, color); // Right
+  // draw four corners
+  drawCircleHelper(x+r    , y+r    , r, 1, color);
+  drawCircleHelper(x+w-r-1, y+r    , r, 2, color);
+  drawCircleHelper(x+w-r-1, y+h-r-1, r, 4, color);
+  drawCircleHelper(x+r    , y+h-r-1, r, 8, color);
+}
+
+// Fill a rounded rectangle
+void Adafruit_GFX::fillRoundRect(int16_t x, int16_t y, int16_t w,
+ int16_t h, int16_t r, uint16_t color) {
+  // smarter version
+  fillRect(x+r, y, w-2*r, h, color);
+
+  // draw four corners
+  fillCircleHelper(x+w-r-1, y+r, r, 1, h-2*r-1, color);
+  fillCircleHelper(x+r    , y+r, r, 2, h-2*r-1, color);
+}
+
+// Draw a triangle
+void Adafruit_GFX::drawTriangle(int16_t x0, int16_t y0,
+ int16_t x1, int16_t y1, int16_t x2, int16_t y2, uint16_t color) {
+  drawLine(x0, y0, x1, y1, color);
+  drawLine(x1, y1, x2, y2, color);
+  drawLine(x2, y2, x0, y0, color);
+}
+
+// Fill a triangle
+void Adafruit_GFX::fillTriangle(int16_t x0, int16_t y0,
+ int16_t x1, int16_t y1, int16_t x2, int16_t y2, uint16_t color) {
+
+  int16_t a, b, y, last;
+
+  // Sort coordinates by Y order (y2 >= y1 >= y0)
+  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) { // Handle awkward all-on-same-line case as its own thing
+    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;
+    drawFastHLine(a, y0, b-a+1, color);
+    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;
+
+  // For upper part of triangle, find scanline crossings for segments
+  // 0-1 and 0-2.  If y1=y2 (flat-bottomed triangle), the scanline y1
+  // is included here (and second loop will be skipped, avoiding a /0
+  // error there), otherwise scanline y1 is skipped here and handled
+  // in the second loop...which also avoids a /0 error here if y0=y1
+  // (flat-topped triangle).
+  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;
+    /* longhand:
+    a = x0 + (x1 - x0) * (y - y0) / (y1 - y0);
+    b = x0 + (x2 - x0) * (y - y0) / (y2 - y0);
+    */
+    if(a > b) _swap_int16_t(a,b);
+    drawFastHLine(a, y, b-a+1, color);
+  }
+
+  // For lower part of triangle, find scanline crossings for segments
+  // 0-2 and 1-2.  This loop is skipped if y1=y2.
+  sa = dx12 * (y - y1);
+  sb = dx02 * (y - y0);
+  for(; y<=y2; y++) {
+    a   = x1 + sa / dy12;
+    b   = x0 + sb / dy02;
+    sa += dx12;
+    sb += dx02;
+    /* longhand:
+    a = x1 + (x2 - x1) * (y - y1) / (y2 - y1);
+    b = x0 + (x2 - x0) * (y - y0) / (y2 - y0);
+    */
+    if(a > b) _swap_int16_t(a,b);
+    drawFastHLine(a, y, b-a+1, color);
+  }
+}
+
+
+// Draw a 1-bit image (bitmap) at the specified (x,y) position from the
+// provided bitmap buffer using the specified
+// foreground color (unset bits are transparent).
+void Adafruit_GFX::drawBitmap(int16_t x, int16_t y, 
+	 const uint8_t *bitmap, int16_t w, int16_t h, uint16_t color) {
+
+  int16_t i, j, byteWidth = (w + 7) / 8;
+  uint8_t byte;
+
+  for(j=0; j<h; j++) {
+    for(i=0; i<w; i++ ) {
+      if(i & 7) byte <<= 1;
+      else      byte   = bitmap[j * byteWidth + i / 8];
+      if(byte & 0x80) drawPixel(x+i, y+j, color);
+    }
+  }
+}
+
+// Draw a 1-bit image (bitmap) at the specified (x,y) position from the
+// provided bitmap buffer using the specified
+// foreground (for set bits) and background (for clear bits) colors.
+void Adafruit_GFX::drawBitmap(int16_t x, int16_t y,
+     	const uint8_t *bitmap, int16_t w, int16_t h, uint16_t color, uint16_t bg) {
+
+  int16_t i, j, byteWidth = (w + 7) / 8;
+  uint8_t byte;
+
+  for(j=0; j<h; j++) {
+    for(i=0; i<w; i++ ) {
+      if(i & 7) byte <<= 1;
+      else      byte   = bitmap[j * byteWidth + i / 8];
+      if(byte & 0x80) drawPixel(x+i, y+j, color);
+      else            drawPixel(x+i, y+j, bg);
+    }
+  }
+}
+
+//Draw XBitMap Files (*.xbm), exported from GIMP,
+//Usage: Export from GIMP to *.xbm, rename *.xbm to *.c and open in editor.
+//C Array can be directly used with this function
+void Adafruit_GFX::drawXBitmap(int16_t x, int16_t y,
+ const uint8_t *bitmap, int16_t w, int16_t h, uint16_t color) {
+
+  int16_t i, j, byteWidth = (w + 7) / 8;
+  uint8_t byte;
+
+  for(j=0; j<h; j++) {
+    for(i=0; i<w; i++ ) {
+      if(i & 7) byte >>= 1;
+      else      byte   = pgm_read_byte(bitmap + j * byteWidth + i / 8);
+      if(byte & 0x01) drawPixel(x+i, y+j, color);
+    }
+  }
+}
+
+size_t Adafruit_GFX::write(uint8_t c) {
+  if(!gfxFont) { // 'Classic' built-in font
+
+    if(c == '\n') {
+      cursor_y += textsize*8;
+      cursor_x  = 0;
+    } else if(c == '\r') {
+      // skip em
+    } else {
+      if(wrap && ((cursor_x + textsize * 6) >= _width)) { // Heading off edge?
+        cursor_x  = 0;            // Reset x to zero
+        cursor_y += textsize * 8; // Advance y one line
+      }
+      drawChar(cursor_x, cursor_y, c, textcolor, textbgcolor, textsize);
+      cursor_x += textsize * 6;
+    }
+
+  } else { // Custom font
+
+    if(c == '\n') {
+      cursor_x  = 0;
+      cursor_y += (int16_t)textsize *
+                  (uint8_t)pgm_read_byte(&gfxFont->yAdvance);
+    } else if(c != '\r') {
+      uint8_t first = pgm_read_byte(&gfxFont->first);
+      if((c >= first) && (c <= (uint8_t)pgm_read_byte(&gfxFont->last))) {
+        uint8_t   c2    = c - pgm_read_byte(&gfxFont->first);
+        GFXglyph *glyph = &(((GFXglyph *)pgm_read_pointer(&gfxFont->glyph))[c2]);
+        uint8_t   w     = pgm_read_byte(&glyph->width),
+                  h     = pgm_read_byte(&glyph->height);
+        if((w > 0) && (h > 0)) { // Is there an associated bitmap?
+          int16_t xo = (int8_t)pgm_read_byte(&glyph->xOffset); // sic
+          if(wrap && ((cursor_x + textsize * (xo + w)) >= _width)) {
+            // Drawing character would go off right edge; wrap to new line
+            cursor_x  = 0;
+            cursor_y += (int16_t)textsize *
+                        (uint8_t)pgm_read_byte(&gfxFont->yAdvance);
+          }
+          drawChar(cursor_x, cursor_y, c, textcolor, textbgcolor, textsize);
+        }
+        cursor_x += pgm_read_byte(&glyph->xAdvance) * (int16_t)textsize;
+      }
+    }
+
+  }
+  return 1;
+}
+
+// Draw a character
+void Adafruit_GFX::drawChar(int16_t x, int16_t y, unsigned char c,
+ uint16_t color, uint16_t bg, uint8_t size) {
+
+  if(!gfxFont) { // 'Classic' built-in font
+
+    if((x >= _width)            || // Clip right
+       (y >= _height)           || // Clip bottom
+       ((x + 6 * size - 1) < 0) || // Clip left
+       ((y + 8 * size - 1) < 0))   // Clip top
+      return;
+
+    for(int8_t i=0; i<6; i++ ) {
+      uint8_t line;
+      if(i < 5) line = pgm_read_byte(font+(c*5)+i);
+      else      line = 0x0;
+      for(int8_t j=0; j<8; j++, line >>= 1) {
+        if(line & 0x1) {
+          if(size == 1) drawPixel(x+i, y+j, color);
+          else          fillRect(x+(i*size), y+(j*size), size, size, color);
+        } else if(bg != color) {
+          if(size == 1) drawPixel(x+i, y+j, bg);
+          else          fillRect(x+i*size, y+j*size, size, size, bg);
+        }
+      }
+    }
+
+  } else { // Custom font
+
+    // Character is assumed previously filtered by write() to eliminate
+    // newlines, returns, non-printable characters, etc.  Calling drawChar()
+    // directly with 'bad' characters of font may cause mayhem!
+
+    c -= pgm_read_byte(&gfxFont->first);
+    GFXglyph *glyph  = &(((GFXglyph *)pgm_read_pointer(&gfxFont->glyph))[c]);
+    uint8_t  *bitmap = (uint8_t *)pgm_read_pointer(&gfxFont->bitmap);
+
+    uint16_t bo = pgm_read_word(&glyph->bitmapOffset);
+    uint8_t  w  = pgm_read_byte(&glyph->width),
+             h  = pgm_read_byte(&glyph->height),
+             xa = pgm_read_byte(&glyph->xAdvance);
+    int8_t   xo = pgm_read_byte(&glyph->xOffset);
+    int8_t   yo = pgm_read_byte(&glyph->yOffset);
+    uint8_t  xx, yy, bits, bit = 0;
+    int16_t  xo16, yo16;
+
+    if(size > 1) {
+      xo16 = xo;
+      yo16 = yo;
+    }
+
+    // Todo: Add character clipping here
+
+    // NOTE: THERE IS NO 'BACKGROUND' COLOR OPTION ON CUSTOM FONTS.
+    // THIS IS ON PURPOSE AND BY DESIGN.  The background color feature
+    // has typically been used with the 'classic' font to overwrite old
+    // screen contents with new data.  This ONLY works because the
+    // characters are a uniform size; it's not a sensible thing to do with
+    // proportionally-spaced fonts with glyphs of varying sizes (and that
+    // may overlap).  To replace previously-drawn text when using a custom
+    // font, use the getTextBounds() function to determine the smallest
+    // rectangle encompassing a string, erase the area with fillRect(),
+    // then draw new text.  This WILL infortunately 'blink' the text, but
+    // is unavoidable.  Drawing 'background' pixels will NOT fix this,
+    // only creates a new set of problems.  Have an idea to work around
+    // this (a canvas object type for MCUs that can afford the RAM and
+    // displays supporting setAddrWindow() and pushColors()), but haven't
+    // implemented this yet.
+
+    for(yy=0; yy<h; yy++) {
+      for(xx=0; xx<w; xx++) {
+        if(!(bit++ & 7)) {
+          bits = pgm_read_byte(&bitmap[bo++]);
+        }
+        if(bits & 0x80) {
+          if(size == 1) {
+            drawPixel(x+xo+xx, y+yo+yy, color);
+          } else {
+            fillRect(x+(xo16+xx)*size, y+(yo16+yy)*size, size, size, color);
+          }
+        }
+        bits <<= 1;
+      }
+    }
+
+  } // End classic vs custom font
+}
+
+void Adafruit_GFX::setCursor(int16_t x, int16_t y) {
+  cursor_x = x;
+  cursor_y = y;
+}
+
+int16_t Adafruit_GFX::getCursorX(void) const {
+  return cursor_x;
+}
+
+int16_t Adafruit_GFX::getCursorY(void) const {
+  return cursor_y;
+}
+
+void Adafruit_GFX::setTextSize(uint8_t s) {
+  textsize = (s > 0) ? s : 1;
+}
+
+void Adafruit_GFX::setTextColor(uint16_t c) {
+  // For 'transparent' background, we'll set the bg
+  // to the same as fg instead of using a flag
+  textcolor = textbgcolor = c;
+}
+
+void Adafruit_GFX::setTextColor(uint16_t c, uint16_t b) {
+  textcolor   = c;
+  textbgcolor = b;
+}
+
+void Adafruit_GFX::setTextWrap(bool w) {
+  wrap = w;
+}
+
+uint8_t Adafruit_GFX::getRotation(void) const {
+  return rotation;
+}
+
+void Adafruit_GFX::setRotation(uint8_t x) {
+  rotation = (x & 3);
+  switch(rotation) {
+   case 0:
+   case 2:
+    _width  = WIDTH;
+    _height = HEIGHT;
+    break;
+   case 1:
+   case 3:
+    _width  = HEIGHT;
+    _height = WIDTH;
+    break;
+  }
+}
+
+
+void Adafruit_GFX::setFont(const GFXfont *f) {
+  if(f) {          // Font struct pointer passed in?
+    if(!gfxFont) { // And no current font struct?
+      // Switching from classic to new font behavior.
+      // Move cursor pos down 6 pixels so it's on baseline.
+      cursor_y += 6;
+    }
+  } else if(gfxFont) { // NULL passed.  Current font struct defined?
+    // Switching from new to classic font behavior.
+    // Move cursor pos up 6 pixels so it's at top-left of char.
+    cursor_y -= 6;
+  }
+  gfxFont = (GFXfont *)f;
+}
+
+// Pass string and a cursor position, returns UL corner and W,H.
+void Adafruit_GFX::getTextBounds(char *str, int16_t x, int16_t y,
+ int16_t *x1, int16_t *y1, uint16_t *w, uint16_t *h) {
+  uint8_t c; // Current character
+
+  *x1 = x;
+  *y1 = y;
+  *w  = *h = 0;
+
+  if(gfxFont) {
+
+    GFXglyph *glyph;
+    uint8_t   first = pgm_read_byte(&gfxFont->first),
+              last  = pgm_read_byte(&gfxFont->last),
+              gw, gh, xa;
+    int8_t    xo, yo;
+    int16_t   minx = _width, miny = _height, maxx = -1, maxy = -1,
+              gx1, gy1, gx2, gy2, ts = (int16_t)textsize,
+              ya = ts * (uint8_t)pgm_read_byte(&gfxFont->yAdvance);
+
+    while((c = *str++)) {
+      if(c != '\n') { // Not a newline
+        if(c != '\r') { // Not a carriage return, is normal char
+          if((c >= first) && (c <= last)) { // Char present in current font
+            c    -= first;
+            glyph = &(((GFXglyph *)pgm_read_pointer(&gfxFont->glyph))[c]);
+            gw    = pgm_read_byte(&glyph->width);
+            gh    = pgm_read_byte(&glyph->height);
+            xa    = pgm_read_byte(&glyph->xAdvance);
+            xo    = pgm_read_byte(&glyph->xOffset);
+            yo    = pgm_read_byte(&glyph->yOffset);
+            if(wrap && ((x + (((int16_t)xo + gw) * ts)) >= _width)) {
+              // Line wrap
+              x  = 0;  // Reset x to 0
+              y += ya; // Advance y by 1 line
+            }
+            gx1 = x   + xo * ts;
+            gy1 = y   + yo * ts;
+            gx2 = gx1 + gw * ts - 1;
+            gy2 = gy1 + gh * ts - 1;
+            if(gx1 < minx) minx = gx1;
+            if(gy1 < miny) miny = gy1;
+            if(gx2 > maxx) maxx = gx2;
+            if(gy2 > maxy) maxy = gy2;
+            x += xa * ts;
+          }
+        } // Carriage return = do nothing
+      } else { // Newline
+        x  = 0;  // Reset x
+        y += ya; // Advance y by 1 line
+      }
+    }
+    // End of string
+    *x1 = minx;
+    *y1 = miny;
+    if(maxx >= minx) *w  = maxx - minx + 1;
+    if(maxy >= miny) *h  = maxy - miny + 1;
+
+  } else { // Default font
+
+    uint16_t lineWidth = 0, maxWidth = 0; // Width of current, all lines
+
+    while((c = *str++)) {
+      if(c != '\n') { // Not a newline
+        if(c != '\r') { // Not a carriage return, is normal char
+          if(wrap && ((x + textsize * 6) >= _width)) {
+            x  = 0;            // Reset x to 0
+            y += textsize * 8; // Advance y by 1 line
+            if(lineWidth > maxWidth) maxWidth = lineWidth; // Save widest line
+            lineWidth  = textsize * 6; // First char on new line
+          } else { // No line wrap, just keep incrementing X
+            lineWidth += textsize * 6; // Includes interchar x gap
+          }
+        } // Carriage return = do nothing
+      } else { // Newline
+        x  = 0;            // Reset x to 0
+        y += textsize * 8; // Advance y by 1 line
+        if(lineWidth > maxWidth) maxWidth = lineWidth; // Save widest line
+        lineWidth = 0;     // Reset lineWidth for new line
+      }
+    }
+    // End of string
+    if(lineWidth) y += textsize * 8; // Add height of last (or only) line
+    if(lineWidth > maxWidth) maxWidth = lineWidth; // Is the last or only line the widest?
+    *w = maxWidth - 1;               // Don't include last interchar x gap
+    *h = y - *y1;
+
+  } // End classic vs custom font
+}
+
+
+
+void Adafruit_GFX::print(const char* str) {
+    const char* p = str;
+    while (*p!=0)
+    	write(*p++);
+}
+
+void Adafruit_GFX::println(const char* str) {
+	print(str);
+	write('\n');
+}
+
+// Return the size of the display (per current rotation)
+int16_t Adafruit_GFX::width(void) const {
+  return _width;
+}
+
+int16_t Adafruit_GFX::height(void) const {
+  return _height;
+}
+
+void Adafruit_GFX::invertDisplay(bool i) {
+  // Do nothing, must be subclassed if supported by hardware
+}
+
+
+/***************************************************************************/
+
diff -r ec3a2da01f40 -r b483e656bd14 oled/Adafruit_GFX.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/oled/Adafruit_GFX.h	Sun Jun 16 04:44:35 2019 +0000
@@ -0,0 +1,96 @@
+#ifndef _ADAFRUIT_GFX_H
+#define _ADAFRUIT_GFX_H
+
+#include <stdlib.h>
+
+#include "gfxfont.h"
+
+class Adafruit_GFX {
+
+ public:
+
+  Adafruit_GFX(int16_t w, int16_t h); // Constructor
+
+  // This MUST be defined by the subclass:
+  virtual void drawPixel(int16_t x, int16_t y, uint16_t color) = 0;
+
+  // These MAY be overridden by the subclass to provide device-specific
+  // optimized code.  Otherwise 'generic' versions are used.
+  virtual void
+    drawLine(int16_t x0, int16_t y0, int16_t x1, int16_t y1, uint16_t color),
+    drawFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color),
+    drawFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color),
+    drawRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color),
+    fillRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color),
+    fillScreen(uint16_t color),
+    invertDisplay(bool i);
+
+  // These exist only with Adafruit_GFX (no subclass overrides)
+  void
+    drawCircle(int16_t x0, int16_t y0, int16_t r, uint16_t color),
+    drawCircleHelper(int16_t x0, int16_t y0, int16_t r, uint8_t cornername,
+      uint16_t color),
+    fillCircle(int16_t x0, int16_t y0, int16_t r, uint16_t color),
+    fillCircleHelper(int16_t x0, int16_t y0, int16_t r, uint8_t cornername,
+      int16_t delta, uint16_t color),
+    drawTriangle(int16_t x0, int16_t y0, int16_t x1, int16_t y1,
+      int16_t x2, int16_t y2, uint16_t color),
+    fillTriangle(int16_t x0, int16_t y0, int16_t x1, int16_t y1,
+      int16_t x2, int16_t y2, uint16_t color),
+    drawRoundRect(int16_t x0, int16_t y0, int16_t w, int16_t h,
+      int16_t radius, uint16_t color),
+    fillRoundRect(int16_t x0, int16_t y0, int16_t w, int16_t h,
+      int16_t radius, uint16_t color),
+
+    drawBitmap(int16_t x, int16_t y, const uint8_t *bitmap, int16_t w, int16_t h, uint16_t color),
+    drawBitmap(int16_t x, int16_t y, const uint8_t *bitmap, int16_t w, int16_t h, uint16_t color, uint16_t bg),
+
+    drawXBitmap(int16_t x, int16_t y, const uint8_t *bitmap,
+      int16_t w, int16_t h, uint16_t color),
+    drawChar(int16_t x, int16_t y, unsigned char c, uint16_t color,
+      uint16_t bg, uint8_t size),
+    setCursor(int16_t x, int16_t y),
+    setTextColor(uint16_t c),
+    setTextColor(uint16_t c, uint16_t bg),
+    setTextSize(uint8_t s),
+    setTextWrap(bool w),
+    setRotation(uint8_t r),
+    cp437(bool x=true),
+    setFont(const GFXfont *f = NULL),
+    getTextBounds(char *string, int16_t x, int16_t y,
+      int16_t *x1, int16_t *y1, uint16_t *w, uint16_t *h),
+    getTextBounds(const char *s, int16_t x, int16_t y,
+      int16_t *x1, int16_t *y1, uint16_t *w, uint16_t *h),
+	print(const char* str),
+    println(const char* str);
+
+  virtual size_t write(uint8_t);
+
+  int16_t height(void) const;
+  int16_t width(void) const;
+
+  uint8_t getRotation(void) const;
+
+  // get current cursor position (get rotation safe maximum values, using: width() for x, height() for y)
+  int16_t getCursorX(void) const;
+  int16_t getCursorY(void) const;
+
+ protected:
+  const int16_t
+    WIDTH, HEIGHT;   // This is the 'raw' display w/h - never changes
+  int16_t
+    _width, _height, // Display w/h as modified by current rotation
+    cursor_x, cursor_y;
+  uint16_t
+    textcolor, textbgcolor;
+  uint8_t
+    textsize,
+    rotation;
+  bool
+    wrap,   // If set, 'wrap' text at right edge of display
+    _cp437; // If set, use correct CP437 charset (default is off)
+  GFXfont
+    *gfxFont;
+};
+
+#endif // _ADAFRUIT_GFX_H
diff -r ec3a2da01f40 -r b483e656bd14 oled/FreeSans9pt7b.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/oled/FreeSans9pt7b.h	Sun Jun 16 04:44:35 2019 +0000
@@ -0,0 +1,201 @@
+const uint8_t FreeSans9pt7bBitmaps[]  = {
+  0xFF, 0xFF, 0xF8, 0xC0, 0xDE, 0xF7, 0x20, 0x09, 0x86, 0x41, 0x91, 0xFF,
+  0x13, 0x04, 0xC3, 0x20, 0xC8, 0xFF, 0x89, 0x82, 0x61, 0x90, 0x10, 0x1F,
+  0x14, 0xDA, 0x3D, 0x1E, 0x83, 0x40, 0x78, 0x17, 0x08, 0xF4, 0x7A, 0x35,
+  0x33, 0xF0, 0x40, 0x20, 0x38, 0x10, 0xEC, 0x20, 0xC6, 0x20, 0xC6, 0x40,
+  0xC6, 0x40, 0x6C, 0x80, 0x39, 0x00, 0x01, 0x3C, 0x02, 0x77, 0x02, 0x63,
+  0x04, 0x63, 0x04, 0x77, 0x08, 0x3C, 0x0E, 0x06, 0x60, 0xCC, 0x19, 0x81,
+  0xE0, 0x18, 0x0F, 0x03, 0x36, 0xC2, 0xD8, 0x73, 0x06, 0x31, 0xE3, 0xC4,
+  0xFE, 0x13, 0x26, 0x6C, 0xCC, 0xCC, 0xC4, 0x66, 0x23, 0x10, 0x8C, 0x46,
+  0x63, 0x33, 0x33, 0x32, 0x66, 0x4C, 0x80, 0x25, 0x7E, 0xA5, 0x00, 0x30,
+  0xC3, 0x3F, 0x30, 0xC3, 0x0C, 0xD6, 0xF0, 0xC0, 0x08, 0x44, 0x21, 0x10,
+  0x84, 0x42, 0x11, 0x08, 0x00, 0x3C, 0x66, 0x42, 0xC3, 0xC3, 0xC3, 0xC3,
+  0xC3, 0xC3, 0xC3, 0x42, 0x66, 0x3C, 0x11, 0x3F, 0x33, 0x33, 0x33, 0x33,
+  0x30, 0x3E, 0x31, 0xB0, 0x78, 0x30, 0x18, 0x1C, 0x1C, 0x1C, 0x18, 0x18,
+  0x10, 0x08, 0x07, 0xF8, 0x3C, 0x66, 0xC3, 0xC3, 0x03, 0x06, 0x1C, 0x07,
+  0x03, 0xC3, 0xC3, 0x66, 0x3C, 0x0C, 0x18, 0x71, 0x62, 0xC9, 0xA3, 0x46,
+  0xFE, 0x18, 0x30, 0x60, 0xC0, 0x7F, 0x20, 0x10, 0x08, 0x08, 0x07, 0xF3,
+  0x8C, 0x03, 0x01, 0x80, 0xF0, 0x6C, 0x63, 0xE0, 0x1E, 0x31, 0x98, 0x78,
+  0x0C, 0x06, 0xF3, 0x8D, 0x83, 0xC1, 0xE0, 0xD0, 0x6C, 0x63, 0xE0, 0xFF,
+  0x03, 0x02, 0x06, 0x04, 0x0C, 0x08, 0x18, 0x18, 0x18, 0x10, 0x30, 0x30,
+  0x3E, 0x31, 0xB0, 0x78, 0x3C, 0x1B, 0x18, 0xF8, 0xC6, 0xC1, 0xE0, 0xF0,
+  0x6C, 0x63, 0xE0, 0x3C, 0x66, 0xC2, 0xC3, 0xC3, 0xC3, 0x67, 0x3B, 0x03,
+  0x03, 0xC2, 0x66, 0x3C, 0xC0, 0x00, 0x30, 0xC0, 0x00, 0x00, 0x64, 0xA0,
+  0x00, 0x81, 0xC7, 0x8E, 0x0C, 0x07, 0x80, 0x70, 0x0E, 0x01, 0x80, 0xFF,
+  0x80, 0x00, 0x1F, 0xF0, 0x00, 0x70, 0x0E, 0x01, 0xC0, 0x18, 0x38, 0x71,
+  0xC0, 0x80, 0x00, 0x3E, 0x31, 0xB0, 0x78, 0x30, 0x18, 0x18, 0x38, 0x18,
+  0x18, 0x0C, 0x00, 0x00, 0x01, 0x80, 0x03, 0xF0, 0x06, 0x0E, 0x06, 0x01,
+  0x86, 0x00, 0x66, 0x1D, 0xBB, 0x31, 0xCF, 0x18, 0xC7, 0x98, 0x63, 0xCC,
+  0x31, 0xE6, 0x11, 0xB3, 0x99, 0xCC, 0xF7, 0x86, 0x00, 0x01, 0x80, 0x00,
+  0x70, 0x40, 0x0F, 0xE0, 0x06, 0x00, 0xF0, 0x0F, 0x00, 0x90, 0x19, 0x81,
+  0x98, 0x10, 0x83, 0x0C, 0x3F, 0xC2, 0x04, 0x60, 0x66, 0x06, 0xC0, 0x30,
+  0xFF, 0x18, 0x33, 0x03, 0x60, 0x6C, 0x0D, 0x83, 0x3F, 0xC6, 0x06, 0xC0,
+  0x78, 0x0F, 0x01, 0xE0, 0x6F, 0xF8, 0x1F, 0x86, 0x19, 0x81, 0xA0, 0x3C,
+  0x01, 0x80, 0x30, 0x06, 0x00, 0xC0, 0x68, 0x0D, 0x83, 0x18, 0x61, 0xF0,
+  0xFF, 0x18, 0x33, 0x03, 0x60, 0x3C, 0x07, 0x80, 0xF0, 0x1E, 0x03, 0xC0,
+  0x78, 0x0F, 0x03, 0x60, 0xCF, 0xF0, 0xFF, 0xE0, 0x30, 0x18, 0x0C, 0x06,
+  0x03, 0xFD, 0x80, 0xC0, 0x60, 0x30, 0x18, 0x0F, 0xF8, 0xFF, 0xC0, 0xC0,
+  0xC0, 0xC0, 0xC0, 0xFE, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0x0F, 0x83,
+  0x0E, 0x60, 0x66, 0x03, 0xC0, 0x0C, 0x00, 0xC1, 0xFC, 0x03, 0xC0, 0x36,
+  0x03, 0x60, 0x73, 0x0F, 0x0F, 0x10, 0xC0, 0x78, 0x0F, 0x01, 0xE0, 0x3C,
+  0x07, 0x80, 0xFF, 0xFE, 0x03, 0xC0, 0x78, 0x0F, 0x01, 0xE0, 0x3C, 0x06,
+  0xFF, 0xFF, 0xFF, 0xC0, 0x06, 0x0C, 0x18, 0x30, 0x60, 0xC1, 0x83, 0x07,
+  0x8F, 0x1E, 0x27, 0x80, 0xC0, 0xD8, 0x33, 0x0C, 0x63, 0x0C, 0xC1, 0xB8,
+  0x3F, 0x07, 0x30, 0xC3, 0x18, 0x63, 0x06, 0x60, 0x6C, 0x0C, 0xC0, 0xC0,
+  0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xFF, 0xE0,
+  0x3F, 0x01, 0xFC, 0x1F, 0xE0, 0xFD, 0x05, 0xEC, 0x6F, 0x63, 0x79, 0x13,
+  0xCD, 0x9E, 0x6C, 0xF1, 0x47, 0x8E, 0x3C, 0x71, 0x80, 0xE0, 0x7C, 0x0F,
+  0xC1, 0xE8, 0x3D, 0x87, 0x98, 0xF1, 0x1E, 0x33, 0xC3, 0x78, 0x6F, 0x07,
+  0xE0, 0x7C, 0x0E, 0x0F, 0x81, 0x83, 0x18, 0x0C, 0xC0, 0x6C, 0x01, 0xE0,
+  0x0F, 0x00, 0x78, 0x03, 0xC0, 0x1B, 0x01, 0x98, 0x0C, 0x60, 0xC0, 0xF8,
+  0x00, 0xFF, 0x30, 0x6C, 0x0F, 0x03, 0xC0, 0xF0, 0x6F, 0xF3, 0x00, 0xC0,
+  0x30, 0x0C, 0x03, 0x00, 0xC0, 0x00, 0x0F, 0x81, 0x83, 0x18, 0x0C, 0xC0,
+  0x6C, 0x01, 0xE0, 0x0F, 0x00, 0x78, 0x03, 0xC0, 0x1B, 0x01, 0x98, 0x6C,
+  0x60, 0xC0, 0xFB, 0x00, 0x08, 0xFF, 0x8C, 0x0E, 0xC0, 0x6C, 0x06, 0xC0,
+  0x6C, 0x0C, 0xFF, 0x8C, 0x0E, 0xC0, 0x6C, 0x06, 0xC0, 0x6C, 0x06, 0xC0,
+  0x70, 0x3F, 0x18, 0x6C, 0x0F, 0x03, 0xC0, 0x1E, 0x01, 0xF0, 0x0E, 0x00,
+  0xF0, 0x3C, 0x0D, 0x86, 0x3F, 0x00, 0xFF, 0x86, 0x03, 0x01, 0x80, 0xC0,
+  0x60, 0x30, 0x18, 0x0C, 0x06, 0x03, 0x01, 0x80, 0xC0, 0xC0, 0x78, 0x0F,
+  0x01, 0xE0, 0x3C, 0x07, 0x80, 0xF0, 0x1E, 0x03, 0xC0, 0x78, 0x0F, 0x01,
+  0xB0, 0x61, 0xF0, 0xC0, 0x6C, 0x0D, 0x81, 0x10, 0x63, 0x0C, 0x61, 0x04,
+  0x60, 0xCC, 0x19, 0x01, 0x60, 0x3C, 0x07, 0x00, 0x60, 0xC1, 0x81, 0x30,
+  0xE1, 0x98, 0x70, 0xCC, 0x28, 0x66, 0x26, 0x21, 0x13, 0x30, 0xC8, 0x98,
+  0x6C, 0x4C, 0x14, 0x34, 0x0A, 0x1A, 0x07, 0x07, 0x03, 0x03, 0x80, 0x81,
+  0x80, 0x60, 0x63, 0x0C, 0x30, 0xC1, 0x98, 0x0F, 0x00, 0xE0, 0x06, 0x00,
+  0xF0, 0x19, 0x01, 0x98, 0x30, 0xC6, 0x0E, 0x60, 0x60, 0xC0, 0x36, 0x06,
+  0x30, 0xC3, 0x0C, 0x19, 0x81, 0xD8, 0x0F, 0x00, 0x60, 0x06, 0x00, 0x60,
+  0x06, 0x00, 0x60, 0x06, 0x00, 0xFF, 0xC0, 0x60, 0x30, 0x0C, 0x06, 0x03,
+  0x01, 0xC0, 0x60, 0x30, 0x18, 0x06, 0x03, 0x00, 0xFF, 0xC0, 0xFB, 0x6D,
+  0xB6, 0xDB, 0x6D, 0xB6, 0xE0, 0x84, 0x10, 0x84, 0x10, 0x84, 0x10, 0x84,
+  0x10, 0x80, 0xED, 0xB6, 0xDB, 0x6D, 0xB6, 0xDB, 0xE0, 0x30, 0x60, 0xA2,
+  0x44, 0xD8, 0xA1, 0x80, 0xFF, 0xC0, 0xC6, 0x30, 0x7E, 0x71, 0xB0, 0xC0,
+  0x60, 0xF3, 0xDB, 0x0D, 0x86, 0xC7, 0x3D, 0xC0, 0xC0, 0x60, 0x30, 0x1B,
+  0xCE, 0x36, 0x0F, 0x07, 0x83, 0xC1, 0xE0, 0xF0, 0x7C, 0x6D, 0xE0, 0x3C,
+  0x66, 0xC3, 0xC0, 0xC0, 0xC0, 0xC0, 0xC3, 0x66, 0x3C, 0x03, 0x03, 0x03,
+  0x3B, 0x67, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0x67, 0x3B, 0x3C, 0x66,
+  0xC3, 0xC3, 0xFF, 0xC0, 0xC0, 0xC3, 0x66, 0x3C, 0x36, 0x6F, 0x66, 0x66,
+  0x66, 0x66, 0x60, 0x3B, 0x67, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0x67,
+  0x3B, 0x03, 0x03, 0xC6, 0x7C, 0xC0, 0xC0, 0xC0, 0xDE, 0xE3, 0xC3, 0xC3,
+  0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xFF, 0xFF, 0xC0, 0x30, 0x03,
+  0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0xE0, 0xC0, 0x60, 0x30, 0x18, 0x4C,
+  0x46, 0x63, 0x61, 0xF0, 0xEC, 0x62, 0x31, 0x98, 0x6C, 0x30, 0xFF, 0xFF,
+  0xFF, 0xC0, 0xDE, 0xF7, 0x1C, 0xF0, 0xC7, 0x86, 0x3C, 0x31, 0xE1, 0x8F,
+  0x0C, 0x78, 0x63, 0xC3, 0x1E, 0x18, 0xC0, 0xDE, 0xE3, 0xC3, 0xC3, 0xC3,
+  0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0x3C, 0x66, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3,
+  0xC3, 0x66, 0x3C, 0xDE, 0x71, 0xB0, 0x78, 0x3C, 0x1E, 0x0F, 0x07, 0x83,
+  0xE3, 0x6F, 0x30, 0x18, 0x0C, 0x00, 0x3B, 0x67, 0xC3, 0xC3, 0xC3, 0xC3,
+  0xC3, 0xC3, 0x67, 0x3B, 0x03, 0x03, 0x03, 0xDF, 0x31, 0x8C, 0x63, 0x18,
+  0xC6, 0x00, 0x3E, 0xE3, 0xC0, 0xC0, 0xE0, 0x3C, 0x07, 0xC3, 0xE3, 0x7E,
+  0x66, 0xF6, 0x66, 0x66, 0x66, 0x67, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3,
+  0xC3, 0xC3, 0xC7, 0x7B, 0xC1, 0xA0, 0x98, 0xCC, 0x42, 0x21, 0xB0, 0xD0,
+  0x28, 0x1C, 0x0C, 0x00, 0xC6, 0x1E, 0x38, 0x91, 0xC4, 0xCA, 0x66, 0xD3,
+  0x16, 0xD0, 0xA6, 0x87, 0x1C, 0x38, 0xC0, 0xC6, 0x00, 0x43, 0x62, 0x36,
+  0x1C, 0x18, 0x1C, 0x3C, 0x26, 0x62, 0x43, 0xC1, 0x21, 0x98, 0xCC, 0x42,
+  0x61, 0xB0, 0xD0, 0x38, 0x1C, 0x0C, 0x06, 0x03, 0x01, 0x03, 0x00, 0xFE,
+  0x0C, 0x30, 0xC1, 0x86, 0x18, 0x20, 0xC1, 0xFC, 0x36, 0x66, 0x66, 0x6E,
+  0xCE, 0x66, 0x66, 0x66, 0x30, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0xC6, 0x66,
+  0x66, 0x67, 0x37, 0x66, 0x66, 0x66, 0xC0, 0x61, 0x24, 0x38 };
+
+const GFXglyph FreeSans9pt7bGlyphs[]  = {
+  {     0,   0,   0,   5,    0,    1 },   // 0x20 ' '
+  {     0,   2,  13,   6,    2,  -12 },   // 0x21 '!'
+  {     4,   5,   4,   6,    1,  -12 },   // 0x22 '"'
+  {     7,  10,  12,  10,    0,  -11 },   // 0x23 '#'
+  {    22,   9,  16,  10,    1,  -13 },   // 0x24 '$'
+  {    40,  16,  13,  16,    1,  -12 },   // 0x25 '%'
+  {    66,  11,  13,  12,    1,  -12 },   // 0x26 '&'
+  {    84,   2,   4,   4,    1,  -12 },   // 0x27 '''
+  {    85,   4,  17,   6,    1,  -12 },   // 0x28 '('
+  {    94,   4,  17,   6,    1,  -12 },   // 0x29 ')'
+  {   103,   5,   5,   7,    1,  -12 },   // 0x2A '*'
+  {   107,   6,   8,  11,    3,   -7 },   // 0x2B '+'
+  {   113,   2,   4,   5,    2,    0 },   // 0x2C ','
+  {   114,   4,   1,   6,    1,   -4 },   // 0x2D '-'
+  {   115,   2,   1,   5,    1,    0 },   // 0x2E '.'
+  {   116,   5,  13,   5,    0,  -12 },   // 0x2F '/'
+  {   125,   8,  13,  10,    1,  -12 },   // 0x30 '0'
+  {   138,   4,  13,  10,    3,  -12 },   // 0x31 '1'
+  {   145,   9,  13,  10,    1,  -12 },   // 0x32 '2'
+  {   160,   8,  13,  10,    1,  -12 },   // 0x33 '3'
+  {   173,   7,  13,  10,    2,  -12 },   // 0x34 '4'
+  {   185,   9,  13,  10,    1,  -12 },   // 0x35 '5'
+  {   200,   9,  13,  10,    1,  -12 },   // 0x36 '6'
+  {   215,   8,  13,  10,    0,  -12 },   // 0x37 '7'
+  {   228,   9,  13,  10,    1,  -12 },   // 0x38 '8'
+  {   243,   8,  13,  10,    1,  -12 },   // 0x39 '9'
+  {   256,   2,  10,   5,    1,   -9 },   // 0x3A ':'
+  {   259,   3,  12,   5,    1,   -8 },   // 0x3B ';'
+  {   264,   9,   9,  11,    1,   -8 },   // 0x3C '<'
+  {   275,   9,   4,  11,    1,   -5 },   // 0x3D '='
+  {   280,   9,   9,  11,    1,   -8 },   // 0x3E '>'
+  {   291,   9,  13,  10,    1,  -12 },   // 0x3F '?'
+  {   306,  17,  16,  18,    1,  -12 },   // 0x40 '@'
+  {   340,  12,  13,  12,    0,  -12 },   // 0x41 'A'
+  {   360,  11,  13,  12,    1,  -12 },   // 0x42 'B'
+  {   378,  11,  13,  13,    1,  -12 },   // 0x43 'C'
+  {   396,  11,  13,  13,    1,  -12 },   // 0x44 'D'
+  {   414,   9,  13,  11,    1,  -12 },   // 0x45 'E'
+  {   429,   8,  13,  11,    1,  -12 },   // 0x46 'F'
+  {   442,  12,  13,  14,    1,  -12 },   // 0x47 'G'
+  {   462,  11,  13,  13,    1,  -12 },   // 0x48 'H'
+  {   480,   2,  13,   5,    2,  -12 },   // 0x49 'I'
+  {   484,   7,  13,  10,    1,  -12 },   // 0x4A 'J'
+  {   496,  11,  13,  12,    1,  -12 },   // 0x4B 'K'
+  {   514,   8,  13,  10,    1,  -12 },   // 0x4C 'L'
+  {   527,  13,  13,  15,    1,  -12 },   // 0x4D 'M'
+  {   549,  11,  13,  13,    1,  -12 },   // 0x4E 'N'
+  {   567,  13,  13,  14,    1,  -12 },   // 0x4F 'O'
+  {   589,  10,  13,  12,    1,  -12 },   // 0x50 'P'
+  {   606,  13,  14,  14,    1,  -12 },   // 0x51 'Q'
+  {   629,  12,  13,  13,    1,  -12 },   // 0x52 'R'
+  {   649,  10,  13,  12,    1,  -12 },   // 0x53 'S'
+  {   666,   9,  13,  11,    1,  -12 },   // 0x54 'T'
+  {   681,  11,  13,  13,    1,  -12 },   // 0x55 'U'
+  {   699,  11,  13,  12,    0,  -12 },   // 0x56 'V'
+  {   717,  17,  13,  17,    0,  -12 },   // 0x57 'W'
+  {   745,  12,  13,  12,    0,  -12 },   // 0x58 'X'
+  {   765,  12,  13,  12,    0,  -12 },   // 0x59 'Y'
+  {   785,  10,  13,  11,    1,  -12 },   // 0x5A 'Z'
+  {   802,   3,  17,   5,    1,  -12 },   // 0x5B '['
+  {   809,   5,  13,   5,    0,  -12 },   // 0x5C '\'
+  {   818,   3,  17,   5,    0,  -12 },   // 0x5D ']'
+  {   825,   7,   7,   8,    1,  -12 },   // 0x5E '^'
+  {   832,  10,   1,  10,    0,    3 },   // 0x5F '_'
+  {   834,   4,   3,   5,    0,  -12 },   // 0x60 '`'
+  {   836,   9,  10,  10,    1,   -9 },   // 0x61 'a'
+  {   848,   9,  13,  10,    1,  -12 },   // 0x62 'b'
+  {   863,   8,  10,   9,    1,   -9 },   // 0x63 'c'
+  {   873,   8,  13,  10,    1,  -12 },   // 0x64 'd'
+  {   886,   8,  10,  10,    1,   -9 },   // 0x65 'e'
+  {   896,   4,  13,   5,    1,  -12 },   // 0x66 'f'
+  {   903,   8,  14,  10,    1,   -9 },   // 0x67 'g'
+  {   917,   8,  13,  10,    1,  -12 },   // 0x68 'h'
+  {   930,   2,  13,   4,    1,  -12 },   // 0x69 'i'
+  {   934,   4,  17,   4,    0,  -12 },   // 0x6A 'j'
+  {   943,   9,  13,   9,    1,  -12 },   // 0x6B 'k'
+  {   958,   2,  13,   4,    1,  -12 },   // 0x6C 'l'
+  {   962,  13,  10,  15,    1,   -9 },   // 0x6D 'm'
+  {   979,   8,  10,  10,    1,   -9 },   // 0x6E 'n'
+  {   989,   8,  10,  10,    1,   -9 },   // 0x6F 'o'
+  {   999,   9,  13,  10,    1,   -9 },   // 0x70 'p'
+  {  1014,   8,  13,  10,    1,   -9 },   // 0x71 'q'
+  {  1027,   5,  10,   6,    1,   -9 },   // 0x72 'r'
+  {  1034,   8,  10,   9,    1,   -9 },   // 0x73 's'
+  {  1044,   4,  12,   5,    1,  -11 },   // 0x74 't'
+  {  1050,   8,  10,  10,    1,   -9 },   // 0x75 'u'
+  {  1060,   9,  10,   9,    0,   -9 },   // 0x76 'v'
+  {  1072,  13,  10,  13,    0,   -9 },   // 0x77 'w'
+  {  1089,   8,  10,   9,    0,   -9 },   // 0x78 'x'
+  {  1099,   9,  14,   9,    0,   -9 },   // 0x79 'y'
+  {  1115,   7,  10,   9,    1,   -9 },   // 0x7A 'z'
+  {  1124,   4,  17,   6,    1,  -12 },   // 0x7B '{'
+  {  1133,   2,  17,   4,    2,  -12 },   // 0x7C '|'
+  {  1138,   4,  17,   6,    1,  -12 },   // 0x7D '}'
+  {  1147,   7,   3,   9,    1,   -7 } }; // 0x7E '~'
+
+const GFXfont FreeSans9pt7b  = {
+  (uint8_t  *)FreeSans9pt7bBitmaps,
+  (GFXglyph *)FreeSans9pt7bGlyphs,
+  0x20, 0x7E, 22 };
+
+// Approx. 1822 bytes
diff -r ec3a2da01f40 -r b483e656bd14 oled/SSD1306-Library.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/oled/SSD1306-Library.cpp	Sun Jun 16 04:44:35 2019 +0000
@@ -0,0 +1,525 @@
+/*
+ * SSD1306-Library.cpp
+ *
+ *  Created on: 19 Apr 2017
+ *  Author: ebj
+ *
+ *  I2C version
+ *     CS   GND
+ *     DC   GND  for i2c addr 0x3C, VCC for addr 0x3D
+ *     RES   Vcc
+ */
+
+#include "mbed.h"
+
+#include "SSD1306-Library.h"
+
+extern Serial pc;
+
+extern "C" {
+}
+
+#define NUM_ELEMENTS(x)   ((sizeof x)/(sizeof x[0]))
+
+
+I2C i2c(I2C_SDA, I2C_SCL);
+DigitalOut rst(D9); //D13);         //reset pin on D13
+
+
+// the memory buffer for the LCD
+static uint8_t buffer[SSD1306_LCDHEIGHT * SSD1306_LCDWIDTH / 8];
+
+volatile uint8_t dma_pause = 0;
+
+SSD1306::SSD1306(int16_t w, int16_t h) : Adafruit_GFX(w, h) {
+}
+
+#define ssd1306_swap(a, b) { int16_t t = a; a = b; b = t; }
+
+void SSD1306::hw_setup() {
+   i2c.frequency(400000);
+}
+
+
+// the most basic function, set a single pixel
+void SSD1306::drawPixel(int16_t x, int16_t y, uint16_t color) {
+   if ((x < 0) || (x >= width()) || (y < 0) || (y >= height()))
+      return;
+
+   // check rotation, move pixel around if necessary
+   switch (rotation) {
+   case 1:
+      ssd1306_swap(x, y);
+      x = WIDTH - x - 1;
+      break;
+   case 2:
+      x = WIDTH - x - 1;
+      y = HEIGHT - y - 1;
+      break;
+   case 3:
+      ssd1306_swap(x, y);
+      y = HEIGHT - y - 1;
+      break;
+   }
+
+   // x is which column
+   uint8_t *p = &buffer[x + (y/8)*SSD1306_LCDWIDTH];
+   uint8_t v = 1 << (y & 7);
+
+   switch (color) {
+   case WHITE:
+      *p |= v;
+      break;
+   case BLACK:
+      *p &= ~v;
+      break;
+   case INVERSE:
+      *p ^= v;
+      break;
+   }
+
+}
+
+void SSD1306::_sendData(const uint8_t *blk, uint32_t len, bool isData) {
+    const uint8_t *p = blk;
+
+   //pc.printf("SendData...\r\n");
+    // now send the data
+    uint8_t control = 0x00 | (isData ? 0x40 : 0x00);
+
+ 
+    if (isData) {
+      i2c.start();
+      //pc.printf("%0.2x ", *p);
+       i2c.write(0x3C<<1);
+       
+       //control |= 0x80;
+       i2c.write(control);
+      
+       for (int32_t i=0; i<len; i++, p++) {
+          //pc.printf("%0.2x ", *p);
+           int error = i2c.write(*p);
+           //int error = 1;
+           //wait(0.1);
+           if (error != 1)
+               pc.printf("I2C error: %0.2d\r\n", error);
+       }
+       i2c.stop();
+
+    } else {
+       for (int32_t i=0; i<len; i++, p++) {
+          i2c.start();
+          //pc.printf("%0.2x ", *p);
+           i2c.write(0x3C<<1);
+           i2c.write(control);
+           int error = i2c.write(*p);
+           //int error = 1;
+           //wait(0.1);
+           i2c.stop();
+           if (error != 1)
+               pc.printf("I2C error: %0.2d\r\n", error);
+       }
+    }
+}
+
+void SSD1306::sendCommands(const uint8_t *blk, uint32_t len) {
+   _sendData(blk, len, false);
+}
+
+void SSD1306::sendData(const uint8_t *blk, uint32_t len) {
+   _sendData(blk, len, true);
+}
+
+void SSD1306::begin(bool reset) {
+    if (reset) {      //pulse the reset pin -- maybe replace with RC network
+       rst = 1;
+       wait_ms(1);
+       rst = 0;
+       wait_ms(10);
+       rst = 1;   
+    }
+       
+   const uint8_t cmds[] = {
+      SSD1306_DISPLAYOFF,
+      SSD1306_SETDISPLAYCLOCKDIV,
+      0x80,                                   // the suggested ratio 0x80
+      SSD1306_SETMULTIPLEX,
+      SSD1306_LCDHEIGHT - 1,
+      SSD1306_SETDISPLAYOFFSET,
+      0x0,                                    // no offset
+      SSD1306_SETSTARTLINE | 0x0,             // line #0
+      SSD1306_CHARGEPUMP,
+      0x14,
+      SSD1306_MEMORYMODE,
+      0x00,                                   // 0x0 act like ks0108
+      SSD1306_SEGREMAP | 0x1,
+      SSD1306_COMSCANDEC,
+      SSD1306_SETCOMPINS,
+      0x12,
+      SSD1306_SETCONTRAST,
+      0xCF,
+      SSD1306_SETPRECHARGE,
+      0xF1,
+      SSD1306_SETVCOMDETECT,
+      0x40,
+      SSD1306_DISPLAYALLON_RESUME,
+      SSD1306_NORMALDISPLAY,
+      SSD1306_DEACTIVATE_SCROLL,
+      SSD1306_DISPLAYON                     //--turn on oled panel
+   };
+
+        sendCommands(cmds, NUM_ELEMENTS(cmds));
+
+}
+
+
+void SSD1306::display(void) {
+   const uint8_t cmds[] = {
+      SSD1306_COLUMNADDR,
+      0,               // Column start address (0 = reset)
+      SSD1306_LCDWIDTH - 1,      // Column end address (127 = reset)
+      SSD1306_PAGEADDR,
+      0,             // Page start address (0 = reset)
+      7             // Page end address
+      };
+
+    sendCommands(cmds, NUM_ELEMENTS(cmds));
+   //now send the screen image
+   sendData(buffer, NUM_ELEMENTS(buffer));
+}
+
+void SSD1306::invertDisplay(uint8_t i) {
+   const uint8_t normalCmd[] = { SSD1306_NORMALDISPLAY };
+   const uint8_t invertCmd[] = { SSD1306_INVERTDISPLAY };
+        sendCommands( i ? invertCmd : normalCmd, 1);
+}
+
+
+void SSD1306::_scroll(uint8_t mode, uint8_t start, uint8_t stop) {
+   uint8_t cmds[] = { mode, 0, start, 0, stop, 0, 0xFF, SSD1306_ACTIVATE_SCROLL };
+        sendCommands(cmds, NUM_ELEMENTS(cmds));
+}
+// startscrollright
+// Activate a right handed scroll for rows start through stop
+// Hint, the display is 16 rows tall. To scroll the whole display, run:
+// display.scrollright(0x00, 0x0F)
+void SSD1306::startscrollright(uint8_t start, uint8_t stop) {
+   _scroll(SSD1306_RIGHT_HORIZONTAL_SCROLL, start, stop);
+}
+
+// startscrollleft
+// Activate a right handed scroll for rows start through stop
+// Hint, the display is 16 rows tall. To scroll the whole display, run:
+// display.scrollright(0x00, 0x0F)
+void SSD1306::startscrollleft(uint8_t start, uint8_t stop) {
+   _scroll(SSD1306_LEFT_HORIZONTAL_SCROLL, start, stop);
+}
+
+// startscrolldiagright
+// Activate a diagonal scroll for rows start through stop
+// Hint, the display is 16 rows tall. To scroll the whole display, run:
+// display.scrollright(0x00, 0x0F)
+void SSD1306::startscrolldiagright(uint8_t start, uint8_t stop) {
+    uint8_t cmds[] = { 
+   SSD1306_SET_VERTICAL_SCROLL_AREA,
+   0X00,
+   SSD1306_LCDHEIGHT,
+   SSD1306_VERTICAL_AND_RIGHT_HORIZONTAL_SCROLL,
+   0X00,
+   start,
+   0X00,
+   stop,
+   0X01,
+   SSD1306_ACTIVATE_SCROLL
+    };
+
+    sendCommands(cmds, NUM_ELEMENTS(cmds));
+}
+
+// startscrolldiagleft
+// Activate a diagonal scroll for rows start through stop
+// Hint, the display is 16 rows tall. To scroll the whole display, run:
+// display.scrollright(0x00, 0x0F)
+void SSD1306::startscrolldiagleft(uint8_t start, uint8_t stop) {
+    uint8_t cmds[] = { 
+   SSD1306_SET_VERTICAL_SCROLL_AREA,
+   0X00,
+   SSD1306_LCDHEIGHT,
+   SSD1306_VERTICAL_AND_LEFT_HORIZONTAL_SCROLL,
+   0X00,
+   start,
+   0X00,
+   stop,
+   0X01,
+   SSD1306_ACTIVATE_SCROLL
+    };
+
+    sendCommands(cmds, NUM_ELEMENTS(cmds));
+}
+
+
+void SSD1306::stopscroll(void) {
+   const uint8_t cmds[] = { SSD1306_DEACTIVATE_SCROLL };
+        sendCommands(cmds, NUM_ELEMENTS(cmds));
+}
+
+// Dim the display
+// dim = true: display is dimmed
+// dim = false: display is normal
+void SSD1306::dim(bool dim) {
+   // the range of contrast to too small to be really useful
+   // it is useful to dim the display
+   uint8_t cmds[] = {SSD1306_SETCONTRAST, dim ? 0 : 0xCF};
+        sendCommands(cmds, NUM_ELEMENTS(cmds));
+}
+
+// clear everything
+void SSD1306::clearDisplay(void) {
+   memset(buffer, 0, (SSD1306_LCDWIDTH * SSD1306_LCDHEIGHT / 8));
+}
+
+#if 1
+void SSD1306::drawFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color) {
+   bool bSwap = false;
+   switch (rotation) {
+   case 0:
+      // 0 degree rotation, do nothing
+      break;
+   case 1:
+      // 90 degree rotation, swap x & y for rotation, then invert x
+      bSwap = true;
+      ssd1306_swap(x, y);
+      x = WIDTH - x - 1;
+      break;
+   case 2:
+      // 180 degree rotation, invert x and y - then shift y around for height.
+      x = WIDTH - x - 1;
+      y = HEIGHT - y - 1;
+      x -= (w - 1);
+      break;
+   case 3:
+      // 270 degree rotation, swap x & y for rotation, then invert y  and adjust y for w (not to become h)
+      bSwap = true;
+      ssd1306_swap(x, y);
+      y = HEIGHT - y - 1;
+      y -= (w - 1);
+      break;
+   }
+
+   if (bSwap) {
+      drawFastVLineInternal(x, y, w, color);
+   } else {
+      drawFastHLineInternal(x, y, w, color);
+   }
+}
+#endif
+
+
+void SSD1306::drawFastHLineInternal(int16_t x, int16_t y, int16_t w,
+      uint16_t color) {
+   // Do bounds/limit checks
+   if (y < 0 || y >= HEIGHT) {
+      return;
+   }
+
+   // make sure we don't try to draw below 0
+   if (x < 0) {
+      w += x;
+      x = 0;
+   }
+
+   // make sure we don't go off the edge of the display
+   if ((x + w) > WIDTH) {
+      w = (WIDTH - x);
+   }
+
+   // if our width is now negative, punt
+   if (w <= 0) {
+      return;
+   }
+
+   // set up the pointer for  movement through the buffer
+   register uint8_t *pBuf = buffer;
+   // adjust the buffer pointer for the current row
+   pBuf += ((y / 8) * SSD1306_LCDWIDTH);
+   // and offset x columns in
+   pBuf += x;
+
+   register uint8_t mask = 1 << (y & 7);
+
+   switch (color) {
+   case WHITE:
+      while (w--)
+         *pBuf++ |= mask;
+      break;
+   case BLACK:
+      mask = ~mask;
+      while (w--)
+         *pBuf++ &= mask;
+      break;
+   case INVERSE:
+      while (w--)
+         *pBuf++ ^= mask;
+      break;
+   }
+}
+
+void SSD1306::drawFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color) {
+   bool bSwap = false;
+   switch (rotation) {
+   case 0:
+      break;
+   case 1:
+      // 90 degree rotation, swap x & y for rotation, then invert x and adjust x for h (now to become w)
+      bSwap = true;
+      ssd1306_swap(x, y)
+      x = WIDTH - x - 1;
+      x -= (h - 1);
+      break;
+   case 2:
+      // 180 degree rotation, invert x and y - then shift y around for height.
+      x = WIDTH - x - 1;
+      y = HEIGHT - y - 1;
+      y -= (h - 1);
+      break;
+   case 3:
+      // 270 degree rotation, swap x & y for rotation, then invert y
+      bSwap = true;
+      ssd1306_swap(x, y)
+      y = HEIGHT - y - 1;
+      break;
+   }
+
+   if (bSwap) {
+      drawFastHLineInternal(x, y, h, color);
+   } else {
+      drawFastVLineInternal(x, y, h, color);
+   }
+}
+
+void SSD1306::drawFastVLineInternal(int16_t x, int16_t __y, int16_t __h, uint16_t color) {
+
+   // do nothing if we're off the left or right side of the screen
+   if (x < 0 || x >= WIDTH) {
+      return;
+   }
+
+   // make sure we don't try to draw below 0
+   if (__y < 0) {
+      // __y is negative, this will subtract enough from __h to account for __y being 0
+      __h += __y;
+      __y = 0;
+
+   }
+
+   // make sure we don't go past the height of the display
+   if ((__y + __h) > HEIGHT) {
+      __h = (HEIGHT - __y);
+   }
+
+   // if our height is now negative, punt
+   if (__h <= 0) {
+      return;
+   }
+
+   // this display doesn't need ints for coordinates, use local byte registers for faster juggling
+   register uint8_t y = __y;
+   register uint8_t h = __h;
+
+   // set up the pointer for fast movement through the buffer
+   register uint8_t *pBuf = buffer;
+   // adjust the buffer pointer for the current row
+   pBuf += ((y / 8) * SSD1306_LCDWIDTH);
+   // and offset x columns in
+   pBuf += x;
+
+   // do the first partial byte, if necessary - this requires some masking
+   register uint8_t mod = (y & 7);
+   if (mod) {
+      // mask off the high n bits we want to set
+      mod = 8 - mod;
+
+      // note - lookup table results in a nearly 10% performance improvement in fill* functions
+      // register uint8_t mask = ~(0xFF >> (mod));
+      static uint8_t premask[8] = { 0x00, 0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC,
+            0xFE };
+      register uint8_t mask = premask[mod];
+
+      // adjust the mask if we're not going to reach the end of this byte
+      if (h < mod) {
+         mask &= (0XFF >> (mod - h));
+      }
+
+      switch (color) {
+      case WHITE:
+         *pBuf |= mask;
+         break;
+      case BLACK:
+         *pBuf &= ~mask;
+         break;
+      case INVERSE:
+         *pBuf ^= mask;
+         break;
+      }
+
+      // fast exit if we're done here!
+      if (h < mod) {
+         return;
+      }
+
+      h -= mod;
+
+      pBuf += SSD1306_LCDWIDTH;
+   }
+
+   // write solid bytes while we can - effectively doing 8 rows at a time
+   if (h >= 8) {
+      if (color == INVERSE) { // separate copy of the code so we don't impact performance of the black/white write version with an extra comparison per loop
+         do {
+            *pBuf = ~(*pBuf);
+
+            // adjust the buffer forward 8 rows worth of data
+            pBuf += SSD1306_LCDWIDTH;
+
+            // adjust h & y (there's got to be a faster way for me to do this, but this should still help a fair bit for now)
+            h -= 8;
+         } while (h >= 8);
+      } else {
+         // store a local value to work with
+         register uint8_t val = (color == WHITE) ? 255 : 0;
+
+         do {
+            // write our value in
+            *pBuf = val;
+
+            // adjust the buffer forward 8 rows worth of data
+            pBuf += SSD1306_LCDWIDTH;
+
+            // adjust h & y (there's got to be a faster way for me to do this, but this should still help a fair bit for now)
+            h -= 8;
+         } while (h >= 8);
+      }
+   }
+
+   // now do the final partial byte, if necessary
+   if (h) {
+      mod = h & 7;
+      // this time we want to mask the low bits of the byte, vs the high bits we did above
+      // register uint8_t mask = (1 << mod) - 1;
+      // note - lookup table results in a nearly 10% performance improvement in fill* functions
+      static uint8_t postmask[8] = { 0x00, 0x01, 0x03, 0x07, 0x0F, 0x1F, 0x3F,
+            0x7F };
+      register uint8_t mask = postmask[mod];
+      switch (color) {
+      case WHITE:
+         *pBuf |= mask;
+         break;
+      case BLACK:
+         *pBuf &= ~mask;
+         break;
+      case INVERSE:
+         *pBuf ^= mask;
+         break;
+      }
+   }
+}
\ No newline at end of file
diff -r ec3a2da01f40 -r b483e656bd14 oled/SSD1306-Library.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/oled/SSD1306-Library.h	Sun Jun 16 04:44:35 2019 +0000
@@ -0,0 +1,112 @@
+/*
+ * SSD1306-Libary.h
+ *
+ *  Created on: Jan 1, 2017
+ *      Author: johnsone
+ */
+
+#ifndef SOURCE_SSD1306_LIBARY_H_
+#define SOURCE_SSD1306_LIBARY_H_
+
+#include "Adafruit_GFX.h"
+
+#include <stdint.h>
+
+#define SSD1306_LCDWIDTH                  128
+#define SSD1306_LCDHEIGHT                 64
+
+#define BLACK 0
+#define WHITE 1
+#define INVERSE 2
+
+#define SSD1306_SETCONTRAST 0x81
+#define SSD1306_DISPLAYALLON_RESUME 0xA4
+#define SSD1306_DISPLAYALLON 0xA5
+#define SSD1306_NORMALDISPLAY 0xA6
+#define SSD1306_INVERTDISPLAY 0xA7
+#define SSD1306_DISPLAYOFF 0xAE
+#define SSD1306_DISPLAYON 0xAF
+
+#define SSD1306_SETDISPLAYOFFSET 0xD3
+#define SSD1306_SETCOMPINS 0xDA
+
+#define SSD1306_SETVCOMDETECT 0xDB
+
+#define SSD1306_SETDISPLAYCLOCKDIV 0xD5
+#define SSD1306_SETPRECHARGE 0xD9
+
+#define SSD1306_SETMULTIPLEX 0xA8
+
+#define SSD1306_SETLOWCOLUMN 0x00
+#define SSD1306_SETHIGHCOLUMN 0x10
+
+#define SSD1306_SETSTARTLINE 0x40
+
+#define SSD1306_MEMORYMODE 0x20
+#define SSD1306_COLUMNADDR 0x21
+#define SSD1306_PAGEADDR   0x22
+
+#define SSD1306_COMSCANINC 0xC0
+#define SSD1306_COMSCANDEC 0xC8
+
+#define SSD1306_SEGREMAP 0xA0
+
+#define SSD1306_CHARGEPUMP 0x8D
+
+// Scrolling #defines
+#define SSD1306_ACTIVATE_SCROLL 0x2F
+#define SSD1306_DEACTIVATE_SCROLL 0x2E
+#define SSD1306_SET_VERTICAL_SCROLL_AREA 0xA3
+#define SSD1306_RIGHT_HORIZONTAL_SCROLL 0x26
+#define SSD1306_LEFT_HORIZONTAL_SCROLL 0x27
+#define SSD1306_VERTICAL_AND_RIGHT_HORIZONTAL_SCROLL 0x29
+#define SSD1306_VERTICAL_AND_LEFT_HORIZONTAL_SCROLL 0x2A
+
+
+class SSD1306 : public Adafruit_GFX {
+  public:
+	SSD1306(int16_t w=SSD1306_LCDWIDTH, int16_t h=SSD1306_LCDHEIGHT);
+
+	void drawPixel(int16_t x, int16_t y, uint16_t color);
+
+	void hw_setup();
+
+	void begin(bool reset=true);
+	void display(void);
+
+	void clearDisplay(void);
+	void invertDisplay(uint8_t i);
+	void startscrollleft(uint8_t start, uint8_t stop);
+	void startscrollright(uint8_t start, uint8_t stop);
+	void startscrolldiagright(uint8_t start, uint8_t stop);
+	void startscrolldiagleft(uint8_t start, uint8_t stop);
+	void stopscroll(void);
+	void dim(bool dim);
+	void drawFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color);
+	void drawFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color);
+
+
+  protected:
+  int16_t
+     _width, _height; // Display w/h as modified by current rotation
+
+   uint8_t
+     textsize,
+     rotation;
+
+  private:
+	void _sendData(const uint8_t *blk, uint32_t len, bool isData);
+	void sendCommands(const uint8_t *blk, uint32_t len);
+	void sendData(const uint8_t *blk, uint32_t len);
+
+	//void ssd1306_command(uint8_t c);
+
+	void drawFastHLineInternal(int16_t x, int16_t y, int16_t w, uint16_t color);
+	void drawFastVLineInternal(int16_t x, int16_t __y, int16_t __h, uint16_t color);
+
+	void _scroll(uint8_t mode, uint8_t start, uint8_t stop);
+};
+
+
+
+#endif /* SOURCE_SSD1306_LIBARY_H_ */
diff -r ec3a2da01f40 -r b483e656bd14 oled/gfxfont.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/oled/gfxfont.h	Sun Jun 16 04:44:35 2019 +0000
@@ -0,0 +1,26 @@
+// Font structures for newer Adafruit_GFX (1.1 and later).
+// Example fonts are included in 'Fonts' directory.
+// To use a font in your Arduino sketch, #include the corresponding .h
+// file and pass address of GFXfont struct to setFont().  Pass NULL to
+// revert to 'classic' fixed-space bitmap font.
+
+#ifndef _GFXFONT_H_
+#define _GFXFONT_H_
+
+#include <stdint.h>
+
+typedef struct { // Data stored PER GLYPH
+	uint16_t bitmapOffset;     // Pointer into GFXfont->bitmap
+	uint8_t  width, height;    // Bitmap dimensions in pixels
+	uint8_t  xAdvance;         // Distance to advance cursor (x axis)
+	int8_t   xOffset, yOffset; // Dist from cursor pos to UL corner
+} GFXglyph;
+
+typedef struct { // Data stored for FONT AS A WHOLE:
+	uint8_t  *bitmap;      // Glyph bitmaps, concatenated
+	GFXglyph *glyph;       // Glyph array
+	uint8_t   first, last; // ASCII extents
+	uint8_t   yAdvance;    // Newline distance (y axis)
+} GFXfont;
+
+#endif // _GFXFONT_H_
diff -r ec3a2da01f40 -r b483e656bd14 oled/glcdfont.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/oled/glcdfont.c	Sun Jun 16 04:44:35 2019 +0000
@@ -0,0 +1,269 @@
+// This is the 'classic' fixed-space bitmap font for Adafruit_GFX since 1.0.
+// See gfxfont.h for newer custom bitmap font info.
+
+#ifndef FONT5X7_H
+#define FONT5X7_H
+
+#define PROGMEM
+
+// Standard ASCII 5x7 font
+
+static const unsigned char font[] PROGMEM = {
+	0x00, 0x00, 0x00, 0x00, 0x00,
+	0x3E, 0x5B, 0x4F, 0x5B, 0x3E,
+	0x3E, 0x6B, 0x4F, 0x6B, 0x3E,
+	0x1C, 0x3E, 0x7C, 0x3E, 0x1C,
+	0x18, 0x3C, 0x7E, 0x3C, 0x18,
+	0x1C, 0x57, 0x7D, 0x57, 0x1C,
+	0x1C, 0x5E, 0x7F, 0x5E, 0x1C,
+	0x00, 0x18, 0x3C, 0x18, 0x00,
+	0xFF, 0xE7, 0xC3, 0xE7, 0xFF,
+	0x00, 0x18, 0x24, 0x18, 0x00,
+	0xFF, 0xE7, 0xDB, 0xE7, 0xFF,
+	0x30, 0x48, 0x3A, 0x06, 0x0E,
+	0x26, 0x29, 0x79, 0x29, 0x26,
+	0x40, 0x7F, 0x05, 0x05, 0x07,
+	0x40, 0x7F, 0x05, 0x25, 0x3F,
+	0x5A, 0x3C, 0xE7, 0x3C, 0x5A,
+	0x7F, 0x3E, 0x1C, 0x1C, 0x08,
+	0x08, 0x1C, 0x1C, 0x3E, 0x7F,
+	0x14, 0x22, 0x7F, 0x22, 0x14,
+	0x5F, 0x5F, 0x00, 0x5F, 0x5F,
+	0x06, 0x09, 0x7F, 0x01, 0x7F,
+	0x00, 0x66, 0x89, 0x95, 0x6A,
+	0x60, 0x60, 0x60, 0x60, 0x60,
+	0x94, 0xA2, 0xFF, 0xA2, 0x94,
+	0x08, 0x04, 0x7E, 0x04, 0x08,
+	0x10, 0x20, 0x7E, 0x20, 0x10,
+	0x08, 0x08, 0x2A, 0x1C, 0x08,
+	0x08, 0x1C, 0x2A, 0x08, 0x08,
+	0x1E, 0x10, 0x10, 0x10, 0x10,
+	0x0C, 0x1E, 0x0C, 0x1E, 0x0C,
+	0x30, 0x38, 0x3E, 0x38, 0x30,
+	0x06, 0x0E, 0x3E, 0x0E, 0x06,
+	0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x5F, 0x00, 0x00,
+	0x00, 0x07, 0x00, 0x07, 0x00,
+	0x14, 0x7F, 0x14, 0x7F, 0x14,
+	0x24, 0x2A, 0x7F, 0x2A, 0x12,
+	0x23, 0x13, 0x08, 0x64, 0x62,
+	0x36, 0x49, 0x56, 0x20, 0x50,
+	0x00, 0x08, 0x07, 0x03, 0x00,
+	0x00, 0x1C, 0x22, 0x41, 0x00,
+	0x00, 0x41, 0x22, 0x1C, 0x00,
+	0x2A, 0x1C, 0x7F, 0x1C, 0x2A,
+	0x08, 0x08, 0x3E, 0x08, 0x08,
+	0x00, 0x80, 0x70, 0x30, 0x00,
+	0x08, 0x08, 0x08, 0x08, 0x08,
+	0x00, 0x00, 0x60, 0x60, 0x00,
+	0x20, 0x10, 0x08, 0x04, 0x02,
+	0x3E, 0x51, 0x49, 0x45, 0x3E,
+	0x00, 0x42, 0x7F, 0x40, 0x00,
+	0x72, 0x49, 0x49, 0x49, 0x46,
+	0x21, 0x41, 0x49, 0x4D, 0x33,
+	0x18, 0x14, 0x12, 0x7F, 0x10,
+	0x27, 0x45, 0x45, 0x45, 0x39,
+	0x3C, 0x4A, 0x49, 0x49, 0x31,
+	0x41, 0x21, 0x11, 0x09, 0x07,
+	0x36, 0x49, 0x49, 0x49, 0x36,
+	0x46, 0x49, 0x49, 0x29, 0x1E,
+	0x00, 0x00, 0x14, 0x00, 0x00,
+	0x00, 0x40, 0x34, 0x00, 0x00,
+	0x00, 0x08, 0x14, 0x22, 0x41,
+	0x14, 0x14, 0x14, 0x14, 0x14,
+	0x00, 0x41, 0x22, 0x14, 0x08,
+	0x02, 0x01, 0x59, 0x09, 0x06,
+	0x3E, 0x41, 0x5D, 0x59, 0x4E,
+	0x7C, 0x12, 0x11, 0x12, 0x7C,
+	0x7F, 0x49, 0x49, 0x49, 0x36,
+	0x3E, 0x41, 0x41, 0x41, 0x22,
+	0x7F, 0x41, 0x41, 0x41, 0x3E,
+	0x7F, 0x49, 0x49, 0x49, 0x41,
+	0x7F, 0x09, 0x09, 0x09, 0x01,
+	0x3E, 0x41, 0x41, 0x51, 0x73,
+	0x7F, 0x08, 0x08, 0x08, 0x7F,
+	0x00, 0x41, 0x7F, 0x41, 0x00,
+	0x20, 0x40, 0x41, 0x3F, 0x01,
+	0x7F, 0x08, 0x14, 0x22, 0x41,
+	0x7F, 0x40, 0x40, 0x40, 0x40,
+	0x7F, 0x02, 0x1C, 0x02, 0x7F,
+	0x7F, 0x04, 0x08, 0x10, 0x7F,
+	0x3E, 0x41, 0x41, 0x41, 0x3E,
+	0x7F, 0x09, 0x09, 0x09, 0x06,
+	0x3E, 0x41, 0x51, 0x21, 0x5E,
+	0x7F, 0x09, 0x19, 0x29, 0x46,
+	0x26, 0x49, 0x49, 0x49, 0x32,
+	0x03, 0x01, 0x7F, 0x01, 0x03,
+	0x3F, 0x40, 0x40, 0x40, 0x3F,
+	0x1F, 0x20, 0x40, 0x20, 0x1F,
+	0x3F, 0x40, 0x38, 0x40, 0x3F,
+	0x63, 0x14, 0x08, 0x14, 0x63,
+	0x03, 0x04, 0x78, 0x04, 0x03,
+	0x61, 0x59, 0x49, 0x4D, 0x43,
+	0x00, 0x7F, 0x41, 0x41, 0x41,
+	0x02, 0x04, 0x08, 0x10, 0x20,
+	0x00, 0x41, 0x41, 0x41, 0x7F,
+	0x04, 0x02, 0x01, 0x02, 0x04,
+	0x40, 0x40, 0x40, 0x40, 0x40,
+	0x00, 0x03, 0x07, 0x08, 0x00,
+	0x20, 0x54, 0x54, 0x78, 0x40,
+	0x7F, 0x28, 0x44, 0x44, 0x38,
+	0x38, 0x44, 0x44, 0x44, 0x28,
+	0x38, 0x44, 0x44, 0x28, 0x7F,
+	0x38, 0x54, 0x54, 0x54, 0x18,
+	0x00, 0x08, 0x7E, 0x09, 0x02,
+	0x18, 0xA4, 0xA4, 0x9C, 0x78,
+	0x7F, 0x08, 0x04, 0x04, 0x78,
+	0x00, 0x44, 0x7D, 0x40, 0x00,
+	0x20, 0x40, 0x40, 0x3D, 0x00,
+	0x7F, 0x10, 0x28, 0x44, 0x00,
+	0x00, 0x41, 0x7F, 0x40, 0x00,
+	0x7C, 0x04, 0x78, 0x04, 0x78,
+	0x7C, 0x08, 0x04, 0x04, 0x78,
+	0x38, 0x44, 0x44, 0x44, 0x38,
+	0xFC, 0x18, 0x24, 0x24, 0x18,
+	0x18, 0x24, 0x24, 0x18, 0xFC,
+	0x7C, 0x08, 0x04, 0x04, 0x08,
+	0x48, 0x54, 0x54, 0x54, 0x24,
+	0x04, 0x04, 0x3F, 0x44, 0x24,
+	0x3C, 0x40, 0x40, 0x20, 0x7C,
+	0x1C, 0x20, 0x40, 0x20, 0x1C,
+	0x3C, 0x40, 0x30, 0x40, 0x3C,
+	0x44, 0x28, 0x10, 0x28, 0x44,
+	0x4C, 0x90, 0x90, 0x90, 0x7C,
+	0x44, 0x64, 0x54, 0x4C, 0x44,
+	0x00, 0x08, 0x36, 0x41, 0x00,
+	0x00, 0x00, 0x77, 0x00, 0x00,
+	0x00, 0x41, 0x36, 0x08, 0x00,
+	0x02, 0x01, 0x02, 0x04, 0x02,
+	0x3C, 0x26, 0x23, 0x26, 0x3C,
+	0x1E, 0xA1, 0xA1, 0x61, 0x12,
+	0x3A, 0x40, 0x40, 0x20, 0x7A,
+	0x38, 0x54, 0x54, 0x55, 0x59,
+	0x21, 0x55, 0x55, 0x79, 0x41,
+	0x22, 0x54, 0x54, 0x78, 0x42, // a-umlaut
+	0x21, 0x55, 0x54, 0x78, 0x40,
+	0x20, 0x54, 0x55, 0x79, 0x40,
+	0x0C, 0x1E, 0x52, 0x72, 0x12,
+	0x39, 0x55, 0x55, 0x55, 0x59,
+	0x39, 0x54, 0x54, 0x54, 0x59,
+	0x39, 0x55, 0x54, 0x54, 0x58,
+	0x00, 0x00, 0x45, 0x7C, 0x41,
+	0x00, 0x02, 0x45, 0x7D, 0x42,
+	0x00, 0x01, 0x45, 0x7C, 0x40,
+	0x7D, 0x12, 0x11, 0x12, 0x7D, // A-umlaut
+	0xF0, 0x28, 0x25, 0x28, 0xF0,
+	0x7C, 0x54, 0x55, 0x45, 0x00,
+	0x20, 0x54, 0x54, 0x7C, 0x54,
+	0x7C, 0x0A, 0x09, 0x7F, 0x49,
+	0x32, 0x49, 0x49, 0x49, 0x32,
+	0x3A, 0x44, 0x44, 0x44, 0x3A, // o-umlaut
+	0x32, 0x4A, 0x48, 0x48, 0x30,
+	0x3A, 0x41, 0x41, 0x21, 0x7A,
+	0x3A, 0x42, 0x40, 0x20, 0x78,
+	0x00, 0x9D, 0xA0, 0xA0, 0x7D,
+	0x3D, 0x42, 0x42, 0x42, 0x3D, // O-umlaut
+	0x3D, 0x40, 0x40, 0x40, 0x3D,
+	0x3C, 0x24, 0xFF, 0x24, 0x24,
+	0x48, 0x7E, 0x49, 0x43, 0x66,
+	0x2B, 0x2F, 0xFC, 0x2F, 0x2B,
+	0xFF, 0x09, 0x29, 0xF6, 0x20,
+	0xC0, 0x88, 0x7E, 0x09, 0x03,
+	0x20, 0x54, 0x54, 0x79, 0x41,
+	0x00, 0x00, 0x44, 0x7D, 0x41,
+	0x30, 0x48, 0x48, 0x4A, 0x32,
+	0x38, 0x40, 0x40, 0x22, 0x7A,
+	0x00, 0x7A, 0x0A, 0x0A, 0x72,
+	0x7D, 0x0D, 0x19, 0x31, 0x7D,
+	0x26, 0x29, 0x29, 0x2F, 0x28,
+	0x26, 0x29, 0x29, 0x29, 0x26,
+	0x30, 0x48, 0x4D, 0x40, 0x20,
+	0x38, 0x08, 0x08, 0x08, 0x08,
+	0x08, 0x08, 0x08, 0x08, 0x38,
+	0x2F, 0x10, 0xC8, 0xAC, 0xBA,
+	0x2F, 0x10, 0x28, 0x34, 0xFA,
+	0x00, 0x00, 0x7B, 0x00, 0x00,
+	0x08, 0x14, 0x2A, 0x14, 0x22,
+	0x22, 0x14, 0x2A, 0x14, 0x08,
+	0x55, 0x00, 0x55, 0x00, 0x55, // #176 (25% block) missing in old code
+	0xAA, 0x55, 0xAA, 0x55, 0xAA, // 50% block
+	0xFF, 0x55, 0xFF, 0x55, 0xFF, // 75% block
+	0x00, 0x00, 0x00, 0xFF, 0x00,
+	0x10, 0x10, 0x10, 0xFF, 0x00,
+	0x14, 0x14, 0x14, 0xFF, 0x00,
+	0x10, 0x10, 0xFF, 0x00, 0xFF,
+	0x10, 0x10, 0xF0, 0x10, 0xF0,
+	0x14, 0x14, 0x14, 0xFC, 0x00,
+	0x14, 0x14, 0xF7, 0x00, 0xFF,
+	0x00, 0x00, 0xFF, 0x00, 0xFF,
+	0x14, 0x14, 0xF4, 0x04, 0xFC,
+	0x14, 0x14, 0x17, 0x10, 0x1F,
+	0x10, 0x10, 0x1F, 0x10, 0x1F,
+	0x14, 0x14, 0x14, 0x1F, 0x00,
+	0x10, 0x10, 0x10, 0xF0, 0x00,
+	0x00, 0x00, 0x00, 0x1F, 0x10,
+	0x10, 0x10, 0x10, 0x1F, 0x10,
+	0x10, 0x10, 0x10, 0xF0, 0x10,
+	0x00, 0x00, 0x00, 0xFF, 0x10,
+	0x10, 0x10, 0x10, 0x10, 0x10,
+	0x10, 0x10, 0x10, 0xFF, 0x10,
+	0x00, 0x00, 0x00, 0xFF, 0x14,
+	0x00, 0x00, 0xFF, 0x00, 0xFF,
+	0x00, 0x00, 0x1F, 0x10, 0x17,
+	0x00, 0x00, 0xFC, 0x04, 0xF4,
+	0x14, 0x14, 0x17, 0x10, 0x17,
+	0x14, 0x14, 0xF4, 0x04, 0xF4,
+	0x00, 0x00, 0xFF, 0x00, 0xF7,
+	0x14, 0x14, 0x14, 0x14, 0x14,
+	0x14, 0x14, 0xF7, 0x00, 0xF7,
+	0x14, 0x14, 0x14, 0x17, 0x14,
+	0x10, 0x10, 0x1F, 0x10, 0x1F,
+	0x14, 0x14, 0x14, 0xF4, 0x14,
+	0x10, 0x10, 0xF0, 0x10, 0xF0,
+	0x00, 0x00, 0x1F, 0x10, 0x1F,
+	0x00, 0x00, 0x00, 0x1F, 0x14,
+	0x00, 0x00, 0x00, 0xFC, 0x14,
+	0x00, 0x00, 0xF0, 0x10, 0xF0,
+	0x10, 0x10, 0xFF, 0x10, 0xFF,
+	0x14, 0x14, 0x14, 0xFF, 0x14,
+	0x10, 0x10, 0x10, 0x1F, 0x00,
+	0x00, 0x00, 0x00, 0xF0, 0x10,
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+	0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
+	0xFF, 0xFF, 0xFF, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0xFF, 0xFF,
+	0x0F, 0x0F, 0x0F, 0x0F, 0x0F,
+	0x38, 0x44, 0x44, 0x38, 0x44,
+	0xFC, 0x4A, 0x4A, 0x4A, 0x34, // sharp-s or beta
+	0x7E, 0x02, 0x02, 0x06, 0x06,
+	0x02, 0x7E, 0x02, 0x7E, 0x02,
+	0x63, 0x55, 0x49, 0x41, 0x63,
+	0x38, 0x44, 0x44, 0x3C, 0x04,
+	0x40, 0x7E, 0x20, 0x1E, 0x20,
+	0x06, 0x02, 0x7E, 0x02, 0x02,
+	0x99, 0xA5, 0xE7, 0xA5, 0x99,
+	0x1C, 0x2A, 0x49, 0x2A, 0x1C,
+	0x4C, 0x72, 0x01, 0x72, 0x4C,
+	0x30, 0x4A, 0x4D, 0x4D, 0x30,
+	0x30, 0x48, 0x78, 0x48, 0x30,
+	0xBC, 0x62, 0x5A, 0x46, 0x3D,
+	0x3E, 0x49, 0x49, 0x49, 0x00,
+	0x7E, 0x01, 0x01, 0x01, 0x7E,
+	0x2A, 0x2A, 0x2A, 0x2A, 0x2A,
+	0x44, 0x44, 0x5F, 0x44, 0x44,
+	0x40, 0x51, 0x4A, 0x44, 0x40,
+	0x40, 0x44, 0x4A, 0x51, 0x40,
+	0x00, 0x00, 0xFF, 0x01, 0x03,
+	0xE0, 0x80, 0xFF, 0x00, 0x00,
+	0x08, 0x08, 0x6B, 0x6B, 0x08,
+	0x36, 0x12, 0x36, 0x24, 0x36,
+	0x06, 0x0F, 0x09, 0x0F, 0x06,
+	0x00, 0x00, 0x18, 0x18, 0x00,
+	0x00, 0x00, 0x10, 0x10, 0x00,
+	0x30, 0x40, 0xFF, 0x01, 0x01,
+	0x00, 0x1F, 0x01, 0x01, 0x1E,
+	0x00, 0x19, 0x1D, 0x17, 0x12,
+	0x00, 0x3C, 0x3C, 0x3C, 0x3C,
+	0x00, 0x00, 0x00, 0x00, 0x00  // #255 NBSP
+};
+#endif // FONT5X7_H