EaPaper Library for EM027BS013

Dependencies:   EM027BS013 TFT_fonts

Fork of EaEpaper by Peter Drescher

Files at this revision

API Documentation at this revision

Comitter:
dreschpe
Date:
Sat Nov 09 23:37:43 2013 +0000
Child:
1:90d18805a8a4
Commit message:
Lib for using a E-Paper display from Pervasive Displays.; There is a interface board from Embedded Artists.; It can handle graphic and text drawing and is using external fonts.

Changed in this revision

EPD.cpp Show annotated file Show diff for this revision Revisions of this file
EPD.h Show annotated file Show diff for this revision Revisions of this file
EaEpaper.cpp Show annotated file Show diff for this revision Revisions of this file
EaEpaper.h Show annotated file Show diff for this revision Revisions of this file
GraphicsDisplay.cpp Show annotated file Show diff for this revision Revisions of this file
GraphicsDisplay.h Show annotated file Show diff for this revision Revisions of this file
TextDisplay.cpp Show annotated file Show diff for this revision Revisions of this file
TextDisplay.h Show annotated file Show diff for this revision Revisions of this file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/EPD.cpp	Sat Nov 09 23:37:43 2013 +0000
@@ -0,0 +1,613 @@
+// Copyright 2013 Pervasive Displays, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at:
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+// express or implied.  See the License for the specific language
+// governing permissions and limitations under the License.
+
+
+
+#include <limits.h>
+
+#include "EPD.h"
+#include "mbed.h"
+#include "BurstSPI.h"
+
+
+// delays - more consistent naming
+#define Delay_ms(ms) wait_ms(ms)
+#define Delay_us(us) wait_us(us)
+
+// inline arrays
+#define ARRAY(type, ...) ((type[]){__VA_ARGS__})
+#define CU8(...) (ARRAY(const uint8_t, __VA_ARGS__))
+
+#define LOW  (0)
+#define HIGH (1)
+#define digitalWrite(pin, state) (pin) = (state)
+#define digitalRead(pin) (pin)
+
+Timer _time;
+#define millis() _time.read_ms()
+#define millis_start() _time.start()
+
+
+//static void PWM_start(int pin);
+//static void PWM_stop(int pin);
+
+//static void SPI_put(uint8_t c);
+//static void SPI_put_wait(uint8_t c, int busy_pin);
+//static void SPI_send(uint8_t cs_pin, const uint8_t *buffer, uint16_t length);
+
+
+EPD_Class::EPD_Class(EPD_size size,
+             PinName panel_on_pin,
+             PinName border_pin,
+             PinName discharge_pin,
+             PinName pwm_pin,
+             PinName reset_pin,
+             PinName busy_pin,
+             PinName chip_select_pin,
+             PinName mosi,
+             PinName miso,
+             PinName sck) :
+    EPD_Pin_PANEL_ON(panel_on_pin),
+    EPD_Pin_BORDER(border_pin),
+    EPD_Pin_DISCHARGE(discharge_pin),
+    EPD_Pin_PWM(pwm_pin),
+    EPD_Pin_RESET(reset_pin),
+    EPD_Pin_BUSY(busy_pin),
+    EPD_Pin_EPD_CS(chip_select_pin),
+    spi_(mosi,miso,sck) {
+
+    this->size = size;
+    this->stage_time = 480; // milliseconds
+    this->lines_per_display = 96;
+    this->dots_per_line = 128;
+    this->bytes_per_line = 128 / 8;
+    this->bytes_per_scan = 96 / 4;
+    this->filler = false;
+    spi_.frequency(12000000);   // 12 MHz SPI clock
+
+    // display size dependant items
+    {
+        static uint8_t cs[] = {0x72, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xff, 0x00};
+        static uint8_t gs[] = {0x72, 0x03};
+        this->channel_select = cs;
+        this->channel_select_length = sizeof(cs);
+        this->gate_source = gs;
+        this->gate_source_length = sizeof(gs);
+    }
+
+    // set up size structure
+    switch (size) {
+    default:
+    case EPD_1_44:  // default so no change
+        break;
+
+    case EPD_2_0: {
+        this->lines_per_display = 96;
+        this->dots_per_line = 200;
+        this->bytes_per_line = 200 / 8;
+        this->bytes_per_scan = 96 / 4;
+        this->filler = true;
+        static uint8_t cs[] = {0x72, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xe0, 0x00};
+        static uint8_t gs[] = {0x72, 0x03};
+        this->channel_select = cs;
+        this->channel_select_length = sizeof(cs);
+        this->gate_source = gs;
+        this->gate_source_length = sizeof(gs);
+        break;
+    }
+
+    case EPD_2_7: {
+        this->stage_time = 630; // milliseconds
+        this->lines_per_display = 176;
+        this->dots_per_line = 264;
+        this->bytes_per_line = 264 / 8;
+        this->bytes_per_scan = 176 / 4;
+        this->filler = true;
+        static uint8_t cs[] = {0x72, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xfe, 0x00, 0x00};
+        static uint8_t gs[] = {0x72, 0x00};
+        this->channel_select = cs;
+        this->channel_select_length = sizeof(cs);
+        this->gate_source = gs;
+        this->gate_source_length = sizeof(gs);
+        break;
+    }
+    }
+
+    this->factored_stage_time = this->stage_time;
+}
+
+
+void EPD_Class::begin() {
+
+    // power up sequence
+    SPI_put(0x00);
+
+    digitalWrite(this->EPD_Pin_RESET, LOW);
+    digitalWrite(this->EPD_Pin_PANEL_ON, LOW);
+    digitalWrite(this->EPD_Pin_DISCHARGE, LOW);
+    digitalWrite(this->EPD_Pin_BORDER, LOW);
+    digitalWrite(this->EPD_Pin_EPD_CS, LOW);
+
+    //PWM_start(this->EPD_Pin_PWM);
+    EPD_Pin_PWM = 0.5;
+    Delay_ms(5);
+    digitalWrite(this->EPD_Pin_PANEL_ON, HIGH);
+    Delay_ms(10);
+
+    digitalWrite(this->EPD_Pin_RESET, HIGH);
+    digitalWrite(this->EPD_Pin_BORDER, HIGH);
+    digitalWrite(this->EPD_Pin_EPD_CS, HIGH);
+    Delay_ms(5);
+
+    digitalWrite(this->EPD_Pin_RESET, LOW);
+    Delay_ms(5);
+
+    digitalWrite(this->EPD_Pin_RESET, HIGH);
+    Delay_ms(5);
+
+    // wait for COG to become ready
+    while (HIGH == digitalRead(this->EPD_Pin_BUSY)) {
+    }
+
+    // channel select
+    Delay_us(10);
+    SPI_send(this->EPD_Pin_EPD_CS, CU8(0x70, 0x01), 2);
+    Delay_us(10);
+    SPI_send(this->EPD_Pin_EPD_CS, this->channel_select, this->channel_select_length);
+
+    // DC/DC frequency
+    Delay_us(10);
+    SPI_send(this->EPD_Pin_EPD_CS, CU8(0x70, 0x06), 2);
+    Delay_us(10);
+    SPI_send(this->EPD_Pin_EPD_CS, CU8(0x72, 0xff), 2);
+
+    // high power mode osc
+    Delay_us(10);
+    SPI_send(this->EPD_Pin_EPD_CS, CU8(0x70, 0x07), 2);
+    Delay_us(10);
+    SPI_send(this->EPD_Pin_EPD_CS, CU8(0x72, 0x9d), 2);
+
+
+    // disable ADC
+    Delay_us(10);
+    SPI_send(this->EPD_Pin_EPD_CS, CU8(0x70, 0x08), 2);
+    Delay_us(10);
+    SPI_send(this->EPD_Pin_EPD_CS, CU8(0x72, 0x00), 2);
+
+    // Vcom level
+    Delay_us(10);
+    SPI_send(this->EPD_Pin_EPD_CS, CU8(0x70, 0x09), 2);
+    Delay_us(10);
+    SPI_send(this->EPD_Pin_EPD_CS, CU8(0x72, 0xd0, 0x00), 3);
+
+    // gate and source voltage levels
+    Delay_us(10);
+    SPI_send(this->EPD_Pin_EPD_CS, CU8(0x70, 0x04), 2);
+    Delay_us(10);
+    SPI_send(this->EPD_Pin_EPD_CS, this->gate_source, this->gate_source_length);
+
+    Delay_ms(5);  //???
+
+    // driver latch on
+    Delay_us(10);
+    SPI_send(this->EPD_Pin_EPD_CS, CU8(0x70, 0x03), 2);
+    Delay_us(10);
+    SPI_send(this->EPD_Pin_EPD_CS, CU8(0x72, 0x01), 2);
+
+    // driver latch off
+    Delay_us(10);
+    SPI_send(this->EPD_Pin_EPD_CS, CU8(0x70, 0x03), 2);
+    Delay_us(10);
+    SPI_send(this->EPD_Pin_EPD_CS, CU8(0x72, 0x00), 2);
+
+    Delay_ms(5);
+
+    // charge pump positive voltage on
+    Delay_us(10);
+    SPI_send(this->EPD_Pin_EPD_CS, CU8(0x70, 0x05), 2);
+    Delay_us(10);
+    SPI_send(this->EPD_Pin_EPD_CS, CU8(0x72, 0x01), 2);
+
+    // final delay before PWM off
+    Delay_ms(30);
+    //PWM_stop(this->EPD_Pin_PWM);
+    EPD_Pin_PWM = 0.0;
+
+    // charge pump negative voltage on
+    Delay_us(10);
+    SPI_send(this->EPD_Pin_EPD_CS, CU8(0x70, 0x05), 2);
+    Delay_us(10);
+    SPI_send(this->EPD_Pin_EPD_CS, CU8(0x72, 0x03), 2);
+
+    Delay_ms(30);
+
+    // Vcom driver on
+    Delay_us(10);
+    SPI_send(this->EPD_Pin_EPD_CS, CU8(0x70, 0x05), 2);
+    Delay_us(10);
+    SPI_send(this->EPD_Pin_EPD_CS, CU8(0x72, 0x0f), 2);
+
+    Delay_ms(30);
+
+    // output enable to disable
+    Delay_us(10);
+    SPI_send(this->EPD_Pin_EPD_CS, CU8(0x70, 0x02), 2);
+    Delay_us(10);
+    SPI_send(this->EPD_Pin_EPD_CS, CU8(0x72, 0x24), 2);
+}
+
+
+void EPD_Class::end() {
+
+    this->frame_fixed(0x55, EPD_normal); // dummy frame
+    this->line(0x7fffu, 0, 0x55, false, EPD_normal); // dummy_line
+
+    Delay_ms(25);
+
+    digitalWrite(this->EPD_Pin_BORDER, LOW);
+    Delay_ms(30);
+
+    digitalWrite(this->EPD_Pin_BORDER, HIGH);
+
+    // latch reset turn on
+    Delay_us(10);
+    SPI_send(this->EPD_Pin_EPD_CS, CU8(0x70, 0x03), 2);
+    Delay_us(10);
+    SPI_send(this->EPD_Pin_EPD_CS, CU8(0x72, 0x01), 2);
+
+    // output enable off
+    Delay_us(10);
+    SPI_send(this->EPD_Pin_EPD_CS, CU8(0x70, 0x02), 2);
+    Delay_us(10);
+    SPI_send(this->EPD_Pin_EPD_CS, CU8(0x72, 0x05), 2);
+
+    // Vcom power off
+    Delay_us(10);
+    SPI_send(this->EPD_Pin_EPD_CS, CU8(0x70, 0x05), 2);
+    Delay_us(10);
+    SPI_send(this->EPD_Pin_EPD_CS, CU8(0x72, 0x0e), 2);
+
+    // power off negative charge pump
+    Delay_us(10);
+    SPI_send(this->EPD_Pin_EPD_CS, CU8(0x70, 0x05), 2);
+    Delay_us(10);
+    SPI_send(this->EPD_Pin_EPD_CS, CU8(0x72, 0x02), 2);
+
+    // discharge
+    Delay_us(10);
+    SPI_send(this->EPD_Pin_EPD_CS, CU8(0x70, 0x04), 2);
+    Delay_us(10);
+    SPI_send(this->EPD_Pin_EPD_CS, CU8(0x72, 0x0c), 2);
+
+    Delay_ms(120);
+
+    // all charge pumps off
+    Delay_us(10);
+    SPI_send(this->EPD_Pin_EPD_CS, CU8(0x70, 0x05), 2);
+    Delay_us(10);
+    SPI_send(this->EPD_Pin_EPD_CS, CU8(0x72, 0x00), 2);
+
+    // turn of osc
+    Delay_us(10);
+    SPI_send(this->EPD_Pin_EPD_CS, CU8(0x70, 0x07), 2);
+    Delay_us(10);
+    SPI_send(this->EPD_Pin_EPD_CS, CU8(0x72, 0x0d), 2);
+
+    // discharge internal - 1
+    Delay_us(10);
+    SPI_send(this->EPD_Pin_EPD_CS, CU8(0x70, 0x04), 2);
+    Delay_us(10);
+    SPI_send(this->EPD_Pin_EPD_CS, CU8(0x72, 0x50), 2);
+
+    Delay_ms(40);
+
+    // discharge internal - 2
+    Delay_us(10);
+    SPI_send(this->EPD_Pin_EPD_CS, CU8(0x70, 0x04), 2);
+    Delay_us(10);
+    SPI_send(this->EPD_Pin_EPD_CS, CU8(0x72, 0xA0), 2);
+
+    Delay_ms(40);
+
+    // discharge internal - 3
+    Delay_us(10);
+    SPI_send(this->EPD_Pin_EPD_CS, CU8(0x70, 0x04), 2);
+    Delay_us(10);
+    SPI_send(this->EPD_Pin_EPD_CS, CU8(0x72, 0x00), 2);
+
+    // turn of power and all signals
+    digitalWrite(this->EPD_Pin_RESET, LOW);
+    digitalWrite(this->EPD_Pin_PANEL_ON, LOW);
+    digitalWrite(this->EPD_Pin_BORDER, LOW);
+    digitalWrite(this->EPD_Pin_EPD_CS, LOW);
+
+    digitalWrite(this->EPD_Pin_DISCHARGE, HIGH);
+
+    SPI_put(0x00);
+
+    Delay_ms(150);
+
+    digitalWrite(this->EPD_Pin_DISCHARGE, LOW);
+}
+
+
+// convert a temperature in Celcius to
+// the scale factor for frame_*_repeat methods
+int EPD_Class::temperature_to_factor_10x(int temperature) {
+    if (temperature <= -10) {
+        return 170;
+    } else if (temperature <= -5) {
+        return 120;
+    } else if (temperature <= 5) {
+        return 80;
+    } else if (temperature <= 10) {
+        return 40;
+    } else if (temperature <= 15) {
+        return 30;
+    } else if (temperature <= 20) {
+        return 20;
+    } else if (temperature <= 40) {
+        return 10;
+    }
+    return 7;
+}
+
+
+// One frame of data is the number of lines * rows. For example:
+// The 1.44” frame of data is 96 lines * 128 dots.
+// The 2” frame of data is 96 lines * 200 dots.
+// The 2.7” frame of data is 176 lines * 264 dots.
+
+// the image is arranged by line which matches the display size
+// so smallest would have 96 * 32 bytes
+
+void EPD_Class::frame_fixed(uint8_t fixed_value, EPD_stage stage) {
+    for (uint8_t line = 0; line < this->lines_per_display ; ++line) {
+        this->line(line, 0, fixed_value, false, stage);
+    }
+}
+
+
+void EPD_Class::frame_data(PROGMEM const uint8_t *image, EPD_stage stage){
+    for (uint8_t line = 0; line < this->lines_per_display ; ++line) {
+        this->line(line, &image[line * this->bytes_per_line], 0, true, stage);
+    }
+}
+
+
+#if defined(EPD_ENABLE_EXTRA_SRAM)
+void EPD_Class::frame_sram(const uint8_t *image, EPD_stage stage){
+    for (uint8_t line = 0; line < this->lines_per_display ; ++line) {
+        this->line(line, &image[line * this->bytes_per_line], 0, false, stage);
+    }
+}
+#endif
+
+
+void EPD_Class::frame_cb(uint32_t address, EPD_reader *reader, EPD_stage stage) {
+    static uint8_t buffer[264 / 8];
+    for (uint8_t line = 0; line < this->lines_per_display; ++line) {
+        reader(buffer, address + line * this->bytes_per_line, this->bytes_per_line);
+        this->line(line, buffer, 0, false, stage);
+    }
+}
+
+void EPD_Class::frame_fixed_repeat(uint8_t fixed_value, EPD_stage stage) {
+    long stage_time = this->factored_stage_time;
+   
+    do {         
+        millis_start();
+        unsigned long t_start = millis();
+        this->frame_fixed(fixed_value, stage);        
+        unsigned long t_end = millis();             
+        if (t_end > t_start) {
+            stage_time -= t_end - t_start;
+        } else {
+            stage_time -= t_start - t_end + 1 + ULONG_MAX;
+        }
+    } while (stage_time > 0);                
+}
+
+
+void EPD_Class::frame_data_repeat(PROGMEM const uint8_t *image, EPD_stage stage) {
+    long stage_time = this->factored_stage_time;
+    do {
+        millis_start();
+        unsigned long t_start = millis();
+        this->frame_data(image, stage);
+        unsigned long t_end = millis();
+        if (t_end > t_start) {
+            stage_time -= t_end - t_start;
+        } else {
+            stage_time -= t_start - t_end + 1 + ULONG_MAX;
+        }
+    } while (stage_time > 0);
+}
+
+
+#if defined(EPD_ENABLE_EXTRA_SRAM)
+void EPD_Class::frame_sram_repeat(const uint8_t *image, EPD_stage stage) {
+    long stage_time = this->factored_stage_time;
+    do {
+        millis_start();
+        unsigned long t_start = millis();
+        this->frame_sram(image, stage);
+        unsigned long t_end = millis();
+        if (t_end > t_start) {
+            stage_time -= t_end - t_start;
+        } else {
+            stage_time -= t_start - t_end + 1 + ULONG_MAX;
+        }
+    } while (stage_time > 0);
+}
+#endif
+
+
+void EPD_Class::frame_cb_repeat(uint32_t address, EPD_reader *reader, EPD_stage stage) {
+    long stage_time = this->factored_stage_time;
+    do {
+        millis_start();
+        unsigned long t_start = millis();
+        this->frame_cb(address, reader, stage);
+        unsigned long t_end = millis();
+        if (t_end > t_start) {
+            stage_time -= t_end - t_start;
+        } else {
+            stage_time -= t_start - t_end + 1 + ULONG_MAX;
+        }
+    } while (stage_time > 0);
+}
+
+
+void EPD_Class::line(uint16_t line, const uint8_t *data, uint8_t fixed_value, bool read_progmem, EPD_stage stage) {
+    // charge pump voltage levels
+    
+    Delay_us(10);
+    SPI_send(this->EPD_Pin_EPD_CS, CU8(0x70, 0x04), 2);
+    Delay_us(10);
+    SPI_send(this->EPD_Pin_EPD_CS, this->gate_source, this->gate_source_length);
+
+    // send data
+    Delay_us(10);
+    SPI_send(this->EPD_Pin_EPD_CS, CU8(0x70, 0x0a), 2);
+    Delay_us(10);
+
+    // CS low
+    digitalWrite(this->EPD_Pin_EPD_CS, LOW);
+    SPI_put_wait(0x72, this->EPD_Pin_BUSY);
+
+    // even pixels
+    for (uint16_t b = this->bytes_per_line; b > 0; --b) {
+        if (0 != data) {
+
+            uint8_t pixels = data[b - 1] & 0xaa;
+
+            switch(stage) {
+            case EPD_compensate:  // B -> W, W -> B (Current Image)
+                pixels = 0xaa | ((pixels ^ 0xaa) >> 1);
+                break;
+            case EPD_white:       // B -> N, W -> W (Current Image)
+                pixels = 0x55 + ((pixels ^ 0xaa) >> 1);
+                break;
+            case EPD_inverse:     // B -> N, W -> B (New Image)
+                pixels = 0x55 | (pixels ^ 0xaa);
+                break;
+            case EPD_normal:       // B -> B, W -> W (New Image)
+                pixels = 0xaa | (pixels >> 1);
+                break;
+            }
+            SPI_put_wait(pixels, this->EPD_Pin_BUSY);
+        } else {
+            SPI_put_wait(fixed_value, this->EPD_Pin_BUSY);
+        }   }
+
+    // scan line
+    for (uint16_t b = 0; b < this->bytes_per_scan; ++b) {
+        if (line / 4 == b) {
+            SPI_put_wait(0xc0 >> (2 * (line & 0x03)), this->EPD_Pin_BUSY);
+        } else {
+            SPI_put_wait(0x00, this->EPD_Pin_BUSY);
+        }
+    }
+
+    // odd pixels
+    for (uint16_t b = 0; b < this->bytes_per_line; ++b) {
+        if (0 != data) {
+
+            uint8_t pixels = data[b] & 0x55;
+
+            switch(stage) {
+            case EPD_compensate:  // B -> W, W -> B (Current Image)
+                pixels = 0xaa | (pixels ^ 0x55);
+                break;
+            case EPD_white:       // B -> N, W -> W (Current Image)
+                pixels = 0x55 + (pixels ^ 0x55);
+                break;
+            case EPD_inverse:     // B -> N, W -> B (New Image)
+                pixels = 0x55 | ((pixels ^ 0x55) << 1);
+                break;
+            case EPD_normal:       // B -> B, W -> W (New Image)
+                pixels = 0xaa | pixels;
+                break;
+            }
+            uint8_t p1 = (pixels >> 6) & 0x03;
+            uint8_t p2 = (pixels >> 4) & 0x03;
+            uint8_t p3 = (pixels >> 2) & 0x03;
+            uint8_t p4 = (pixels >> 0) & 0x03;
+            pixels = (p1 << 0) | (p2 << 2) | (p3 << 4) | (p4 << 6);
+            SPI_put_wait(pixels, this->EPD_Pin_BUSY);
+        } else {
+            SPI_put_wait(fixed_value, this->EPD_Pin_BUSY);
+        }
+    }
+
+    if (this->filler) {
+        SPI_put_wait(0x00, this->EPD_Pin_BUSY);
+    }
+
+    // CS high
+    digitalWrite(this->EPD_Pin_EPD_CS, HIGH);
+
+    // output data to panel
+    Delay_us(10);
+    SPI_send(this->EPD_Pin_EPD_CS, CU8(0x70, 0x02), 2);
+    Delay_us(10);
+    SPI_send(this->EPD_Pin_EPD_CS, CU8(0x72, 0x2f), 2);
+}
+
+
+void EPD_Class::SPI_put(uint8_t c) {
+    
+    spi_.write(c);
+    //spi_.fastWrite(c);
+    
+    
+}
+
+
+
+void EPD_Class::SPI_put_wait(uint8_t c, DigitalIn busy_pin) {
+
+    SPI_put(c);
+
+    // wait for COG ready
+    while (HIGH == digitalRead(busy_pin)) {
+    }
+}
+
+
+void EPD_Class::SPI_send(DigitalOut cs_pin, const uint8_t *buffer, uint16_t length) {
+
+    // CS low
+    digitalWrite(cs_pin, LOW);
+
+    // send all data
+    for (uint16_t i = 0; i < length; ++i) {
+        spi_.fastWrite(*buffer++);
+        spi_.clearRX();
+    }
+
+    // CS high
+    digitalWrite(cs_pin, HIGH);
+}
+
+
+//static void PWM_start(int pin) {
+//    analogWrite(pin, 128);  // 50% duty cycle
+//}
+
+
+//static void PWM_stop(int pin) {
+//    analogWrite(pin, 0);
+//}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/EPD.h	Sat Nov 09 23:37:43 2013 +0000
@@ -0,0 +1,156 @@
+// Copyright 2013 Pervasive Displays, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at:
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+// express or implied.  See the License for the specific language
+// governing permissions and limitations under the License.
+
+#ifndef EPD_H
+#define EPD_H
+
+#include "mbed.h"
+#include "BurstSPI.h"
+
+#define PROGMEM
+
+
+typedef enum {
+    EPD_1_44,        // 128 x 96
+    EPD_2_0,         // 200 x 96
+    EPD_2_7          // 264 x 176
+} EPD_size;
+
+typedef enum {           // Image pixel -> Display pixel
+    EPD_compensate,  // B -> W, W -> B (Current Image)
+    EPD_white,       // B -> N, W -> W (Current Image)
+    EPD_inverse,     // B -> N, W -> B (New Image)
+    EPD_normal       // B -> B, W -> W (New Image)
+} EPD_stage;
+
+typedef void EPD_reader(void *buffer, uint32_t address, uint16_t length);
+
+class EPD_Class {
+private:
+    DigitalOut EPD_Pin_PANEL_ON;
+    DigitalOut EPD_Pin_BORDER;
+    DigitalOut EPD_Pin_DISCHARGE;
+    PwmOut EPD_Pin_PWM;
+    DigitalOut EPD_Pin_RESET;
+    DigitalIn EPD_Pin_BUSY;
+    DigitalOut EPD_Pin_EPD_CS;
+    BurstSPI spi_;    
+
+    EPD_size size;
+    uint16_t stage_time;
+    uint16_t factored_stage_time;
+    uint16_t lines_per_display;
+    uint16_t dots_per_line;
+    uint16_t bytes_per_line;
+    uint16_t bytes_per_scan;
+    PROGMEM const uint8_t *gate_source;
+    uint16_t gate_source_length;
+    PROGMEM const uint8_t *channel_select;
+    uint16_t channel_select_length;
+
+    bool filler;
+    
+    void SPI_put(uint8_t c);
+    void SPI_put_wait(uint8_t c, DigitalIn busy_pin);
+    void SPI_send(DigitalOut cs_pin, const uint8_t *buffer, uint16_t length);
+
+public:
+    // power up and power down the EPD panel
+    void begin();
+    void end();
+
+    void setFactor(int temperature = 25) {
+        this->factored_stage_time = this->stage_time * this->temperature_to_factor_10x(temperature) / 10;
+    }
+
+    // clear display (anything -> white)
+    void clear() {
+        this->frame_fixed_repeat(0xff, EPD_compensate);
+        this->frame_fixed_repeat(0xff, EPD_white);
+        this->frame_fixed_repeat(0xaa, EPD_inverse);
+        this->frame_fixed_repeat(0xaa, EPD_normal);
+    }
+
+    // assuming a clear (white) screen output an image (PROGMEM data)
+    void image(const uint8_t *image) {
+        this->frame_fixed_repeat(0xaa, EPD_compensate);
+        this->frame_fixed_repeat(0xaa, EPD_white);
+        this->frame_data_repeat(image, EPD_inverse);
+        this->frame_data_repeat(image, EPD_normal);
+    }
+
+    // change from old image to new image (PROGMEM data)
+    void image(const uint8_t *old_image, const uint8_t *new_image) {
+        this->frame_data_repeat(old_image, EPD_compensate);
+        this->frame_data_repeat(old_image, EPD_white);
+        this->frame_data_repeat(new_image, EPD_inverse);
+        this->frame_data_repeat(new_image, EPD_normal);
+    }
+
+#if defined(EPD_ENABLE_EXTRA_SRAM)
+
+    // change from old image to new image (SRAM version)
+    void image_sram(const uint8_t *old_image, const uint8_t *new_image) {
+        this->frame_sram_repeat(old_image, EPD_compensate);
+        this->frame_sram_repeat(old_image, EPD_white);
+        this->frame_sram_repeat(new_image, EPD_inverse);
+        this->frame_sram_repeat(new_image, EPD_normal);
+    }
+#endif
+
+    // Low level API calls
+    // ===================
+
+    // single frame refresh
+    void frame_fixed(uint8_t fixed_value, EPD_stage stage);
+    void frame_data(const uint8_t *new_image, EPD_stage stage);
+#if defined(EPD_ENABLE_EXTRA_SRAM)
+    void frame_sram(const uint8_t *new_image, EPD_stage stage);
+#endif
+    void frame_cb(uint32_t address, EPD_reader *reader, EPD_stage stage);
+
+    // stage_time frame refresh
+    void frame_fixed_repeat(uint8_t fixed_value, EPD_stage stage);
+    void frame_data_repeat(const uint8_t *new_image, EPD_stage stage);
+#if defined(EPD_ENABLE_EXTRA_SRAM)
+    void frame_sram_repeat(const uint8_t *new_image, EPD_stage stage);
+#endif
+    void frame_cb_repeat(uint32_t address, EPD_reader *reader, EPD_stage stage);
+
+    // convert temperature to compensation factor
+    int temperature_to_factor_10x(int temperature);
+
+    // single line display - very low-level
+    // also has to handle AVR progmem
+    void line(uint16_t line, const uint8_t *data, uint8_t fixed_value, bool read_progmem, EPD_stage stage);
+
+    // inline static void attachInterrupt();
+    // inline static void detachInterrupt();
+
+    EPD_Class(EPD_size size,
+          PinName panel_on_pin,
+          PinName border_pin,
+          PinName discharge_pin,
+          PinName pwm_pin,
+          PinName reset_pin,
+          PinName busy_pin,
+          PinName chip_select_pin,
+          PinName mosi,
+          PinName miso,
+          PinName sck);
+
+};
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/EaEpaper.cpp	Sat Nov 09 23:37:43 2013 +0000
@@ -0,0 +1,353 @@
+
+#include "EaEpaper.h"
+
+#define EA_IMG_BUF_SZ (5808) // 264 x 176 / 8 = 5808
+
+#define LM75A_ADDRESS (0x92) // 0x49 << 1
+#define LM75A_CMD_TEMP 0x00
+
+static uint8_t _oldImage[EA_IMG_BUF_SZ];
+static uint8_t _newImage[EA_IMG_BUF_SZ];
+
+EaEpaper::EaEpaper(PinName p_on, PinName border, PinName discharge,  PinName reset, PinName busy, PinName cs,
+                   PinName pwm, 
+                   PinName mosi, PinName miso, PinName sck, 
+                   PinName sda, PinName scl, 
+                   const char* name):
+    epd_(EPD_2_7,
+         p_on,  // panel_on_pin
+         border, // border_pin
+         discharge, // discharge_pin
+         pwm, // pwm_pin
+         reset, // reset_pin
+         busy, // busy_pin
+         cs,  // chip_select_pin
+         mosi,  // mosi
+         miso,  // miso
+         sck),  // sck
+    i2c_(sda, scl),
+    GraphicsDisplay(name)
+{
+    draw_mode = NORMAL;
+    memset(_oldImage, 0, EA_IMG_BUF_SZ);
+    memset(_newImage, 0, EA_IMG_BUF_SZ);
+}
+
+
+int EaEpaper::width()
+{
+    return 264;
+}
+
+int EaEpaper::height()
+{
+    return 176;
+}
+
+
+// erase pixel after power up
+void EaEpaper::clear()
+{
+    epd_.begin();
+    epd_.setFactor(readTemperature()/100);
+    epd_.clear();
+    epd_.end();
+
+    memset(_oldImage, 0, EA_IMG_BUF_SZ);
+    memset(_newImage, 0, EA_IMG_BUF_SZ);
+}
+
+// update screen  _newImage -> _oldImage
+void EaEpaper::write_disp(void)
+{
+    epd_.begin();
+    epd_.setFactor(readTemperature()/100);
+    epd_.image(_oldImage, _newImage);
+    epd_.end();
+
+    memcpy(_oldImage, _newImage, EA_IMG_BUF_SZ);
+}
+
+// read LM75A sensor on board to calculate display speed
+int32_t EaEpaper::readTemperature()
+{
+    char buf[2];
+    int32_t t = 0;
+    char reg = LM75A_CMD_TEMP;
+
+    i2c_.write(LM75A_ADDRESS, &reg, 1);
+    i2c_.read(LM75A_ADDRESS, buf, 2);
+
+    t = ((buf[0] << 8) | (buf[1]));
+
+    return ((t * 100) >> 8);
+}
+
+// set one pixel in buffer _newImage
+
+void EaEpaper::pixel(int x, int y, int color)
+{
+    // first check parameter
+    if(x > 263 || y > 175 || x < 0 || y < 0) return;
+
+    if(draw_mode == NORMAL) {
+        if(color == 0)
+            _newImage[(x / 8) + ((y-1) * 33)] &= ~(1 << (x%8));  // erase pixel
+        else
+            _newImage[(x / 8) + ((y-1) * 33)] |= (1 << (x%8));   // set pixel
+    } else { // XOR mode
+        if(color == 1)
+            _newImage[(x / 8) + ((y-1) * 33)] ^= (1 << (x%8));   // xor pixel
+    }
+}
+
+// clear screen
+void EaEpaper::cls(void)
+{
+    memset(_newImage, 0, EA_IMG_BUF_SZ);  // clear display buffer
+}
+
+// print line
+void EaEpaper::line(int x0, int y0, int x1, int y1, int color)
+{
+    int   dx = 0, dy = 0;
+    int   dx_sym = 0, dy_sym = 0;
+    int   dx_x2 = 0, dy_x2 = 0;
+    int   di = 0;
+
+    dx = x1-x0;
+    dy = y1-y0;
+
+    if (dx > 0) {
+        dx_sym = 1;
+    } else {
+        dx_sym = -1;
+    }
+
+    if (dy > 0) {
+        dy_sym = 1;
+    } else {
+        dy_sym = -1;
+    }
+
+    dx = dx_sym*dx;
+    dy = dy_sym*dy;
+
+    dx_x2 = dx*2;
+    dy_x2 = dy*2;
+
+    if (dx >= dy) {
+        di = dy_x2 - dx;
+        while (x0 != x1) {
+
+            pixel(x0, y0, color);
+            x0 += dx_sym;
+            if (di<0) {
+                di += dy_x2;
+            } else {
+                di += dy_x2 - dx_x2;
+                y0 += dy_sym;
+            }
+        }
+        pixel(x0, y0, color);
+    } else {
+        di = dx_x2 - dy;
+        while (y0 != y1) {
+            pixel(x0, y0, color);
+            y0 += dy_sym;
+            if (di < 0) {
+                di += dx_x2;
+            } else {
+                di += dx_x2 - dy_x2;
+                x0 += dx_sym;
+            }
+        }
+        pixel(x0, y0, color);
+    }
+}
+
+// print rect
+void EaEpaper::rect(int x0, int y0, int x1, int y1, int color)
+{
+
+    if (x1 > x0) line(x0,y0,x1,y0,color);
+    else  line(x1,y0,x0,y0,color);
+
+    if (y1 > y0) line(x0,y0,x0,y1,color);
+    else line(x0,y1,x0,y0,color);
+
+    if (x1 > x0) line(x0,y1,x1,y1,color);
+    else  line(x1,y1,x0,y1,color);
+
+    if (y1 > y0) line(x1,y0,x1,y1,color);
+    else line(x1,y1,x1,y0,color);
+}
+
+// print filled rect
+void EaEpaper::fillrect(int x0, int y0, int x1, int y1, int color)
+{
+    int l,c,i;
+    if(x0 > x1) {
+        i = x0;
+        x0 = x1;
+        x1 = i;
+    }
+
+    if(y0 > y1) {
+        i = y0;
+        y0 = y1;
+        y1 = i;
+    }
+
+    for(l = x0; l<= x1; l ++) {
+        for(c = y0; c<= y1; c++) {
+            pixel(l,c,color);
+        }
+    }
+}
+
+// print circle
+void EaEpaper::circle(int x0, int y0, int r, int color)
+{
+    int x = -r, y = 0, err = 2-2*r, e2;
+    do {
+        pixel(x0-x, y0+y,color);
+        pixel(x0+x, y0+y,color);
+        pixel(x0+x, y0-y,color);
+        pixel(x0-x, y0-y,color);
+        e2 = err;
+        if (e2 <= y) {
+            err += ++y*2+1;
+            if (-x == y && e2 <= x) e2 = 0;
+        }
+        if (e2 > x) err += ++x*2+1;
+    } while (x <= 0);
+
+}
+
+// print filled circle
+void EaEpaper::fillcircle(int x0, int y0, int r, int color)
+{
+    int x = -r, y = 0, err = 2-2*r, e2;
+    do {
+        line(x0-x, y0-y, x0-x, y0+y, color);
+        line(x0+x, y0-y, x0+x, y0+y, color);
+        e2 = err;
+        if (e2 <= y) {
+            err += ++y*2+1;
+            if (-x == y && e2 <= x) e2 = 0;
+        }
+        if (e2 > x) err += ++x*2+1;
+    } while (x <= 0);
+}
+
+// set drawing mode
+void EaEpaper::setmode(int mode)
+{
+    draw_mode = mode;
+}
+
+// set cursor position
+void EaEpaper::locate(int x, int y)
+{
+    char_x = x;
+    char_y = y;
+}
+
+// calc char columns
+int EaEpaper::columns()
+{
+    return width() / font[1];
+}
+
+// calc char rows
+int EaEpaper::rows()
+{
+    return height() / font[2];
+}
+
+// print char
+int EaEpaper::_putc(int value)
+{
+    if (value == '\n') {    // new line
+        char_x = 0;
+        char_y = char_y + font[2];
+        if (char_y >= height() - font[2]) {
+            char_y = 0;
+        }
+    } else {
+        character(char_x, char_y, value);
+    }
+    return value;
+}
+
+// paint char out of font
+void EaEpaper::character(int x, int y, int c)
+{
+    unsigned int hor,vert,offset,bpl,j,i,b;
+    unsigned char* zeichen;
+    unsigned char z,w;
+
+    if ((c < 31) || (c > 127)) return;   // test char range
+
+    // read font parameter from start of array
+    offset = font[0];                    // bytes / char
+    hor = font[1];                       // get hor size of font
+    vert = font[2];                      // get vert size of font
+    bpl = font[3];                       // bytes per line
+
+    if (char_x + hor > width()) {
+        char_x = 0;
+        char_y = char_y + vert;
+        if (char_y >= height() - font[2]) {
+            char_y = 0;
+        }
+    }
+
+    zeichen = &font[((c -32) * offset) + 4]; // start of char bitmap
+    w = zeichen[0];                          // width of actual char
+    // construct the char into the buffer
+    for (j=0; j<vert; j++) {  //  vert line
+        for (i=0; i<hor; i++) {   //  horz line
+            z =  zeichen[bpl * i + ((j & 0xF8) >> 3)+1];
+            b = 1 << (j & 0x07);
+            if (( z & b ) == 0x00) {
+                pixel(x+i,y+j,0);
+            } else {
+                pixel(x+i,y+j,1);
+            }
+
+        }
+    }
+
+    char_x += w;
+}
+
+// set actual font
+void EaEpaper::set_font(unsigned char* f)
+{
+    font = f;
+}
+
+void EaEpaper::print_bm(Bitmap bm, int x, int y)
+{
+    int h,v,b;
+    char d;
+
+    for(v=0; v < bm.ySize; v++) {   // lines
+        for(h=0; h < bm.xSize; h++) { // pixel
+            if(h + x > width()) break;
+            if(v + y > height()) break;
+            d = bm.data[bm.Byte_in_Line * v + ((h & 0xF8) >> 3)];
+            b = 0x80 >> (h & 0x07);
+            if((d & b) == 0) {
+                pixel(x+h,y+v,0);
+            } else {
+                pixel(x+h,y+v,1);
+            }
+        }
+    }
+
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/EaEpaper.h	Sat Nov 09 23:37:43 2013 +0000
@@ -0,0 +1,260 @@
+/* mbed library for 264*176 pixel 2.7 INCH E-PAPER DISPLAY from Pervasive Displays
+ * Copyright (c) 2013 Peter Drescher - DC2PD
+ *
+ * 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.
+ */
+
+
+// 09.11.2013   initial Version
+
+#ifndef EAEPAPER_H
+#define EAEPAPER_H
+
+/**
+ * Includes
+ */
+#include "mbed.h"
+#include "EPD.h"
+#include "GraphicsDisplay.h"
+
+// we have to double buffer the display  
+#define EA_IMG_BUF_SZ (5808) // 264 x 176 / 8 = 5808
+
+/** Draw mode
+  * NORMAl
+  * XOR set pixel by xor of the screen
+  */
+enum {NORMAL,XOR};
+
+/** Bitmap
+ */
+struct Bitmap{
+    int xSize;
+    int ySize;
+    int Byte_in_Line;
+    char* data;
+    };
+
+/* color definitions   */
+#define Black           0x0
+#define White           0x1   
+
+/** Display control class, based on GraphicsDisplay and TextDisplay
+ *
+ * Example:
+ * @code
+ * #include "mbed.h"
+ * #include "EaEpaper.h"
+ * #include "Arial28x28.h" 
+ * #include "Arial12x12.h"
+ * #include "font_big.h"
+ * #include "graphics.h"
+
+ * // the E-Paper board from embedded artists has a LM75 temp sensor to compensate the temperature effect. If it is cold the display reacts slower.
+ * // The LM75 need a I2C -> 2 pins : sda and scl 
+ * // The display data is written via SPI -> 3 pins : mosi,miso,sck
+ * // There are also some control signals 
+ * // The pwm pin has to be connected to a PWM enabled pin : pwm
+ * // The other signals are connected to normal IO`s
+ * //              
+ * EaEpaper epaper(PTD7,            // PWR_CTRL
+ *                 PTD6,            // BORDER
+ *                 PTE31,           // DISCHARGE
+ *                 PTA17,           // RESET_DISP
+ *                 PTA16,           // BUSY
+ *                 PTC17,           // SSEL
+ *                 PTD4,            // PWM
+ *                 PTD2,PTD3,PTD1,  // MOSI,MISO,SCLK
+ *                 PTE0,PTE1);      // SDA,SDL 
+ *
+ * int main() {
+ *
+ *   epaper.cls();                                  // clear screen                        
+ *   epaper.set_font((unsigned char*) Arial28x28);  // select the font
+ *   epaper.locate(5,20);                           // set cursor
+ *   epaper.printf("Hello Mbed");                   // print text
+ *   epaper.rect(3,15,150,50,1);                    // draw frame
+ *   epaper.write_disp();                           // update screen
+ *
+ * @endcode
+ */
+ 
+
+class EaEpaper : public GraphicsDisplay  {
+
+public:
+
+    /**
+     * Constructor.
+     */ 
+    EaEpaper(PinName p_on, PinName border, PinName discharge, PinName reset, PinName busy, PinName cs,  // IO-Pins
+             PinName pwm,                                                                               // PWM Pin        
+             PinName mosi, PinName miso, PinName sck,                                                   // SPI
+             PinName sda, PinName scl,                                                                  // I2C
+             const char* name ="E_Paper");
+    
+    /** Get the width of the screen in pixel
+      *
+      * @param
+      * @returns width of screen in pixel
+      *
+      */
+    virtual int width();
+
+    /** Get the height of the screen in pixel
+     *
+     * @returns height of screen in pixel
+     *
+     */
+    virtual int height();
+    
+    
+    /**
+     * Clear the display
+     */    
+    void clear();
+    
+    /**
+     * Write image buffer to display
+     */    
+    void write_disp(void);
+    
+    /**
+     * set or reset a single pixel
+     *
+     * @param x horizontal position
+     * @param y vertical position
+     * @param color : 0 white, 1 black
+     */ 
+    virtual void pixel(int x, int y, int color);
+    
+    /** Fill the screen with white
+     *
+     */ 
+    virtual void cls(void);
+    
+    /** draw a 1 pixel line
+     *
+     * @param x0,y0 start point
+     * @param x1,y1 stop point
+     * @param color  : 0 white, 1 black
+     */  
+    void line(int x0, int y0, int x1, int y1, int color);
+    
+    /** draw a rect
+     *
+     * @param x0,y0 top left corner
+     * @param x1,y1 down right corner
+     * @param color : 0 white, 1 black
+     */    
+    void rect(int x0, int y0, int x1, int y1, int color);
+    
+    /** draw a filled rect
+     *
+     * @param x0,y0 top left corner
+     * @param x1,y1 down right corner
+     * @param color : 0 white, 1 black
+     */  
+    void fillrect(int x0, int y0, int x1, int y1, int color);
+    
+    /** draw a circle
+     *
+     * @param x0,y0 center
+     * @param r radius
+     * @param color : 0 white, 1 black                                                          *
+     */    
+    void circle(int x0, int y0, int r, int color);
+    
+    /** draw a filled circle
+     *
+     * @param x0,y0 center
+     * @param r radius
+     * @param color : 0 white, 1 black                                                                 *
+     */  
+    void fillcircle(int x0, int y0, int r, int color);
+    
+    /** set drawing mode
+     *  @param NORMAL : paint normal color, XOR : paint XOR of current pixels
+     */
+    void setmode(int mode);
+    
+    /** setup cursor position
+     *
+     * @param x x-position (top left)
+     * @param y y-position 
+     */   
+    virtual void locate(int x, int y);
+    
+    /** calculate the max number of char in a line
+     *
+     * @returns max columns
+     * depends on actual font size
+     */ 
+    virtual int columns();
+    
+    /** calculate the max number of columns
+     *
+     * @returns max column
+     * depends on actual font size
+     */   
+    virtual int rows();
+    
+    /** put a char on the screen
+     *
+     * @param value char to print
+     * @returns printed char
+     */
+    virtual int _putc(int value);
+    
+    /** paint a character on given position out of the active font to the screen buffer
+     *
+     * @param x x-position (top left)
+     * @param y y-position 
+     * @param c char code
+     */
+    virtual void character(int x, int y, int c);
+    
+    /** select the font to use
+     *
+     * @param f pointer to font array 
+     *                                                                              
+     *   font array can created with GLCD Font Creator from http://www.mikroe.com
+     *   you have to add 4 parameter at the beginning of the font array to use: 
+     *   - the number of byte / char
+     *   - the vertial size in pixel
+     *   - the horizontal size in pixel
+     *   - the number of byte per vertical line
+     *   you also have to change the array to char[]
+     */  
+    void set_font(unsigned char* f);
+    
+    /** print bitmap to buffer
+      *
+      * @param bm struct Bitmap in flash
+      * @param x  x start
+      * @param y  y start 
+      *
+      */
+    void print_bm(Bitmap bm, int x, int y);
+    
+    
+    unsigned char* font;
+    unsigned int draw_mode;
+    
+ private:
+    
+    EPD_Class epd_;
+    I2C i2c_;
+    unsigned int char_x;
+    unsigned int char_y;
+    int32_t readTemperature();
+    
+};
+ 
+ #endif /* EAEPAPER_H */
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/GraphicsDisplay.cpp	Sat Nov 09 23:37:43 2013 +0000
@@ -0,0 +1,176 @@
+/* mbed GraphicsDisplay Display Library Base Class
+ * Copyright (c) 2007-2009 sford
+ * Released under the MIT License: http://mbed.org/license/mit
+ */
+ 
+#include "GraphicsDisplay.h"
+
+const unsigned char FONT8x8[97][8] = {
+0x08,0x08,0x08,0x00,0x00,0x00,0x00,0x00, // columns, rows, num_bytes_per_char
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // space 0x20
+0x30,0x78,0x78,0x30,0x30,0x00,0x30,0x00, // !
+0x6C,0x6C,0x6C,0x00,0x00,0x00,0x00,0x00, // "
+0x6C,0x6C,0xFE,0x6C,0xFE,0x6C,0x6C,0x00, // #
+0x18,0x3E,0x60,0x3C,0x06,0x7C,0x18,0x00, // $
+0x00,0x63,0x66,0x0C,0x18,0x33,0x63,0x00, // %
+0x1C,0x36,0x1C,0x3B,0x6E,0x66,0x3B,0x00, // &
+0x30,0x30,0x60,0x00,0x00,0x00,0x00,0x00, // '
+0x0C,0x18,0x30,0x30,0x30,0x18,0x0C,0x00, // (
+0x30,0x18,0x0C,0x0C,0x0C,0x18,0x30,0x00, // )
+0x00,0x66,0x3C,0xFF,0x3C,0x66,0x00,0x00, // *
+0x00,0x30,0x30,0xFC,0x30,0x30,0x00,0x00, // +
+0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x30, // ,
+0x00,0x00,0x00,0x7E,0x00,0x00,0x00,0x00, // -
+0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x00, // .
+0x03,0x06,0x0C,0x18,0x30,0x60,0x40,0x00, // / (forward slash)
+0x3E,0x63,0x63,0x6B,0x63,0x63,0x3E,0x00, // 0 0x30
+0x18,0x38,0x58,0x18,0x18,0x18,0x7E,0x00, // 1
+0x3C,0x66,0x06,0x1C,0x30,0x66,0x7E,0x00, // 2
+0x3C,0x66,0x06,0x1C,0x06,0x66,0x3C,0x00, // 3
+0x0E,0x1E,0x36,0x66,0x7F,0x06,0x0F,0x00, // 4
+0x7E,0x60,0x7C,0x06,0x06,0x66,0x3C,0x00, // 5
+0x1C,0x30,0x60,0x7C,0x66,0x66,0x3C,0x00, // 6
+0x7E,0x66,0x06,0x0C,0x18,0x18,0x18,0x00, // 7
+0x3C,0x66,0x66,0x3C,0x66,0x66,0x3C,0x00, // 8
+0x3C,0x66,0x66,0x3E,0x06,0x0C,0x38,0x00, // 9
+0x00,0x18,0x18,0x00,0x00,0x18,0x18,0x00, // :
+0x00,0x18,0x18,0x00,0x00,0x18,0x18,0x30, // ;
+0x0C,0x18,0x30,0x60,0x30,0x18,0x0C,0x00, // <
+0x00,0x00,0x7E,0x00,0x00,0x7E,0x00,0x00, // =
+0x30,0x18,0x0C,0x06,0x0C,0x18,0x30,0x00, // >
+0x3C,0x66,0x06,0x0C,0x18,0x00,0x18,0x00, // ?
+0x3E,0x63,0x6F,0x69,0x6F,0x60,0x3E,0x00, // @ 0x40
+0x18,0x3C,0x66,0x66,0x7E,0x66,0x66,0x00, // A
+0x7E,0x33,0x33,0x3E,0x33,0x33,0x7E,0x00, // B
+0x1E,0x33,0x60,0x60,0x60,0x33,0x1E,0x00, // C
+0x7C,0x36,0x33,0x33,0x33,0x36,0x7C,0x00, // D
+0x7F,0x31,0x34,0x3C,0x34,0x31,0x7F,0x00, // E
+0x7F,0x31,0x34,0x3C,0x34,0x30,0x78,0x00, // F
+0x1E,0x33,0x60,0x60,0x67,0x33,0x1F,0x00, // G
+0x66,0x66,0x66,0x7E,0x66,0x66,0x66,0x00, // H
+0x3C,0x18,0x18,0x18,0x18,0x18,0x3C,0x00, // I
+0x0F,0x06,0x06,0x06,0x66,0x66,0x3C,0x00, // J
+0x73,0x33,0x36,0x3C,0x36,0x33,0x73,0x00, // K
+0x78,0x30,0x30,0x30,0x31,0x33,0x7F,0x00, // L
+0x63,0x77,0x7F,0x7F,0x6B,0x63,0x63,0x00, // M
+0x63,0x73,0x7B,0x6F,0x67,0x63,0x63,0x00, // N
+0x3E,0x63,0x63,0x63,0x63,0x63,0x3E,0x00, // O
+0x7E,0x33,0x33,0x3E,0x30,0x30,0x78,0x00, // P 0x50
+0x3C,0x66,0x66,0x66,0x6E,0x3C,0x0E,0x00, // Q
+0x7E,0x33,0x33,0x3E,0x36,0x33,0x73,0x00, // R
+0x3C,0x66,0x30,0x18,0x0C,0x66,0x3C,0x00, // S
+0x7E,0x5A,0x18,0x18,0x18,0x18,0x3C,0x00, // T
+0x66,0x66,0x66,0x66,0x66,0x66,0x7E,0x00, // U
+0x66,0x66,0x66,0x66,0x66,0x3C,0x18,0x00, // V
+0x63,0x63,0x63,0x6B,0x7F,0x77,0x63,0x00, // W
+0x63,0x63,0x36,0x1C,0x1C,0x36,0x63,0x00, // X
+0x66,0x66,0x66,0x3C,0x18,0x18,0x3C,0x00, // Y
+0x7F,0x63,0x46,0x0C,0x19,0x33,0x7F,0x00, // Z
+0x3C,0x30,0x30,0x30,0x30,0x30,0x3C,0x00, // [
+0x60,0x30,0x18,0x0C,0x06,0x03,0x01,0x00, // \ (back slash)
+0x3C,0x0C,0x0C,0x0C,0x0C,0x0C,0x3C,0x00, // ]
+0x08,0x1C,0x36,0x63,0x00,0x00,0x00,0x00, // ^
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF, // _
+0x18,0x18,0x0C,0x00,0x00,0x00,0x00,0x00, // ` 0x60
+0x00,0x00,0x3C,0x06,0x3E,0x66,0x3B,0x00, // a
+0x70,0x30,0x3E,0x33,0x33,0x33,0x6E,0x00, // b
+0x00,0x00,0x3C,0x66,0x60,0x66,0x3C,0x00, // c
+0x0E,0x06,0x3E,0x66,0x66,0x66,0x3B,0x00, // d
+0x00,0x00,0x3C,0x66,0x7E,0x60,0x3C,0x00, // e
+0x1C,0x36,0x30,0x78,0x30,0x30,0x78,0x00, // f
+0x00,0x00,0x3B,0x66,0x66,0x3E,0x06,0x7C, // g
+0x70,0x30,0x36,0x3B,0x33,0x33,0x73,0x00, // h
+0x18,0x00,0x38,0x18,0x18,0x18,0x3C,0x00, // i
+0x06,0x00,0x06,0x06,0x06,0x66,0x66,0x3C, // j
+0x70,0x30,0x33,0x36,0x3C,0x36,0x73,0x00, // k
+0x38,0x18,0x18,0x18,0x18,0x18,0x3C,0x00, // l
+0x00,0x00,0x66,0x7F,0x7F,0x6B,0x63,0x00, // m
+0x00,0x00,0x7C,0x66,0x66,0x66,0x66,0x00, // n
+0x00,0x00,0x3C,0x66,0x66,0x66,0x3C,0x00, // o
+0x00,0x00,0x6E,0x33,0x33,0x3E,0x30,0x78, // p
+0x00,0x00,0x3B,0x66,0x66,0x3E,0x06,0x0F, // q
+0x00,0x00,0x6E,0x3B,0x33,0x30,0x78,0x00, // r
+0x00,0x00,0x3E,0x60,0x3C,0x06,0x7C,0x00, // s
+0x08,0x18,0x3E,0x18,0x18,0x1A,0x0C,0x00, // t
+0x00,0x00,0x66,0x66,0x66,0x66,0x3B,0x00, // u
+0x00,0x00,0x66,0x66,0x66,0x3C,0x18,0x00, // v
+0x00,0x00,0x63,0x6B,0x7F,0x7F,0x36,0x00, // w
+0x00,0x00,0x63,0x36,0x1C,0x36,0x63,0x00, // x
+0x00,0x00,0x66,0x66,0x66,0x3E,0x06,0x7C, // y
+0x00,0x00,0x7E,0x4C,0x18,0x32,0x7E,0x00, // z
+0x0E,0x18,0x18,0x70,0x18,0x18,0x0E,0x00, // {
+0x0C,0x0C,0x0C,0x00,0x0C,0x0C,0x0C,0x00, // |
+0x70,0x18,0x18,0x0E,0x18,0x18,0x70,0x00, // }
+0x3B,0x6E,0x00,0x00,0x00,0x00,0x00,0x00, // ~
+0x1C,0x36,0x36,0x1C,0x00,0x00,0x00,0x00}; // DEL
+    
+GraphicsDisplay::GraphicsDisplay(const char *name):TextDisplay(name) {
+    foreground(0xFFFF);
+    background(0x0000);
+}
+    
+void GraphicsDisplay::character(int column, int row, int value) { 
+    blitbit(column * 8, row * 8, 8, 8, (char*)&(FONT8x8[value - 0x1F][0]));
+}
+
+void GraphicsDisplay::window(int x, int y, int w, int h) {
+    // current pixel location
+    _x = x;
+    _y = y;
+    // window settings
+    _x1 = x;
+    _x2 = x + w - 1;
+    _y1 = y;
+    _y2 = y + h - 1;
+}
+    
+void GraphicsDisplay::putp(int colour) {
+    // put pixel at current pixel location
+    pixel(_x, _y, colour);
+    // update pixel location based on window settings
+    _x++;
+    if(_x > _x2) {
+        _x = _x1;
+        _y++;
+        if(_y > _y2) {
+            _y = _y1;
+        }
+    }
+}
+
+void GraphicsDisplay::fill(int x, int y, int w, int h, int colour) { 
+    window(x, y, w, h);
+    for(int i=0; i<w*h; i++) {
+        putp(colour);
+    }
+}
+    
+void GraphicsDisplay::cls() {
+    fill(0, 0, width(), height(), _background);
+}
+    
+void GraphicsDisplay::blit(int x, int y, int w, int h, const int *colour) { 
+    window(x, y, w, h);
+    for(int i=0; i<w*h; i++) {
+        putp(colour[i]);
+    }
+}
+    
+void GraphicsDisplay::blitbit(int x, int y, int w, int h, const char* colour) {
+    window(x, y, w, h);
+    for(int i = 0; i < w*h; i++) {
+        char byte = colour[i >> 3];
+        int offset = i & 0x7;
+        int c = ((byte << offset) & 0x80) ? _foreground : _background;
+        putp(c);
+    }
+}
+    
+int GraphicsDisplay::columns() { 
+    return width() / 8; 
+}
+
+int GraphicsDisplay::rows() { 
+    return height() / 8; 
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/GraphicsDisplay.h	Sat Nov 09 23:37:43 2013 +0000
@@ -0,0 +1,55 @@
+/* mbed GraphicsDisplay Display Library Base Class
+ * Copyright (c) 2007-2009 sford
+ * Released under the MIT License: http://mbed.org/license/mit
+ *
+ * A library for providing a common base class for Graphics displays
+ * To port a new display, derive from this class and implement
+ * the constructor (setup the display), pixel (put a pixel
+ * at a location), width and height functions. Everything else
+ * (locate, printf, putc, cls, window, putp, fill, blit, blitbit) 
+ * will come for free. You can also provide a specialised implementation
+ * of window and putp to speed up the results
+ */
+
+#ifndef MBED_GRAPHICSDISPLAY_H
+#define MBED_GRAPHICSDISPLAY_H
+
+#include "TextDisplay.h"
+
+class GraphicsDisplay : public TextDisplay {
+
+public:         
+          
+    GraphicsDisplay(const char* name);
+     
+    virtual void pixel(int x, int y, int colour) = 0;
+    virtual int width() = 0;
+    virtual int height() = 0;
+        
+    virtual void window(int x, int y, int w, int h);
+    virtual void putp(int colour);
+    
+    virtual void cls();
+    virtual void fill(int x, int y, int w, int h, int colour);
+    virtual void blit(int x, int y, int w, int h, const int *colour);    
+    virtual void blitbit(int x, int y, int w, int h, const char* colour);
+    
+    virtual void character(int column, int row, int value);
+    virtual int columns();
+    virtual int rows();
+    
+protected:
+
+    // pixel location
+    short _x;
+    short _y;
+    
+    // window location
+    short _x1;
+    short _x2;
+    short _y1;
+    short _y2;
+
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/TextDisplay.cpp	Sat Nov 09 23:37:43 2013 +0000
@@ -0,0 +1,77 @@
+/* mbed TextDisplay Display Library Base Class
+ * Copyright (c) 2007-2009 sford
+ * Released under the MIT License: http://mbed.org/license/mit
+ */
+ 
+#include "TextDisplay.h"
+
+TextDisplay::TextDisplay(const char *name) : Stream(name){
+    _row = 0;
+    _column = 0;
+    if (name == NULL) {
+        _path = NULL;
+    } else {
+        _path = new char[strlen(name) + 2];
+        sprintf(_path, "/%s", name);
+    }
+}
+    
+int TextDisplay::_putc(int value) {
+    if(value == '\n') {
+        _column = 0;
+        _row++;
+        if(_row >= rows()) {
+            _row = 0;
+        }
+    } else {
+        character(_column, _row, value);
+        _column++;
+        if(_column >= columns()) {
+            _column = 0;
+            _row++;
+            if(_row >= rows()) {
+                _row = 0;
+            }
+        }
+    }
+    return value;
+}
+
+// crude cls implementation, should generally be overwritten in derived class
+void TextDisplay::cls() {
+    locate(0, 0);
+    for(int i=0; i<columns()*rows(); i++) {
+        putc(' ');
+    }
+}
+
+void TextDisplay::locate(int column, int row) {
+    _column = column;
+    _row = row;
+}
+
+int TextDisplay::_getc() {
+    return -1;
+}
+        
+void TextDisplay::foreground(uint16_t colour) {
+    _foreground = colour;
+}
+
+void TextDisplay::background(uint16_t colour) {
+    _background = colour;
+}
+
+bool TextDisplay::claim (FILE *stream) {
+    if ( _path == NULL) {
+        fprintf(stderr, "claim requires a name to be given in the instantioator of the TextDisplay instance!\r\n");
+        return false;
+    }
+    if (freopen(_path, "w", stream) == NULL) {
+        // Failed, should not happen
+        return false;
+    }
+    // make sure we use line buffering
+    setvbuf(stdout, NULL, _IOLBF, columns());
+    return true;
+} 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/TextDisplay.h	Sat Nov 09 23:37:43 2013 +0000
@@ -0,0 +1,80 @@
+/* mbed TextDisplay Library Base Class
+ * Copyright (c) 2007-2009 sford
+ * Released under the MIT License: http://mbed.org/license/mit
+ *
+ * A common base class for Text displays
+ * To port a new display, derive from this class and implement
+ * the constructor (setup the display), character (put a character
+ * at a location), rows and columns (number of rows/cols) functions.
+ * Everything else (locate, printf, putc, cls) will come for free
+ *
+ * The model is the display will wrap at the right and bottom, so you can
+ * keep writing and will always get valid characters. The location is 
+ * maintained internally to the class to make this easy
+ */
+
+#ifndef MBED_TEXTDISPLAY_H
+#define MBED_TEXTDISPLAY_H
+
+#include "mbed.h"
+
+class TextDisplay : public Stream {
+public:
+
+  // functions needing implementation in derived implementation class
+  /** Create a TextDisplay interface
+     *
+     * @param name The name used in the path to access the strean through the filesystem
+     */
+    TextDisplay(const char *name = NULL);
+
+    /** output a character at the given position
+     *
+     * @param column column where charater must be written
+     * @param  row where character must be written
+     * @param c the character to be written to the TextDisplay
+     */
+    virtual void character(int column, int row, int c) = 0;
+
+    /** return number if rows on TextDisplay
+     * @result number of rows
+     */
+    virtual int rows() = 0;
+
+    /** return number if columns on TextDisplay
+    * @result number of rows
+    */
+    virtual int columns() = 0;
+    
+    // functions that come for free, but can be overwritten
+
+    /** redirect output from a stream (stoud, sterr) to  display
+    * @param stream stream that shall be redirected to the TextDisplay
+    */
+    virtual bool claim (FILE *stream);
+
+    /** clear screen
+    */
+    virtual void cls();
+    virtual void locate(int column, int row);
+    virtual void foreground(uint16_t colour);
+    virtual void background(uint16_t colour);
+    // putc (from Stream)
+    // printf (from Stream)
+    
+protected:
+
+    virtual int _putc(int value);
+    virtual int _getc();
+
+    // character location
+    uint16_t _column;
+    uint16_t _row;
+
+    // colours
+    uint16_t _foreground;
+    uint16_t _background;
+    char *_path;
+};
+
+#endif