Drivers for the Nokia LCD screen with a text error fixed and the dimensions of the screen fixed.

Fork of NokiaLCD by Simon Ford

Revision:
3:63ee0e0970ac
Parent:
1:8f005b0dcfa7
--- a/NokiaLCD.cpp	Fri Nov 19 22:12:28 2010 +0000
+++ b/NokiaLCD.cpp	Fri Oct 12 09:33:09 2012 +0000
@@ -1,438 +1,458 @@
-/* mbed Nokia LCD Library
- * Copyright (c) 2007-2010, sford
- */
-
-#include "NokiaLCD.h"
-
-#include "mbed.h"
-
-#define NOKIALCD_ROWS 16
-#define NOKIALCD_COLS 16
-#define NOKIALCD_WIDTH 130
-#define NOKIALCD_HEIGHT 130
-#define NOKIALCD_FREQUENCY 5000000
-
-NokiaLCD::NokiaLCD(PinName mosi, PinName sclk, PinName cs, PinName rst, LCDType type)
-        : _spi(mosi, NC, sclk)
-        , _rst(rst)
-        , _cs(cs) {
-
-    _type = type;
-
-    _row = 0;
-    _column = 0;
-    _foreground = 0x00FFFFFF;
-    _background = 0x00000000;
-
-    reset();
-}
-
-void NokiaLCD::reset() {
-
-    // setup the SPI interface and bring display out of reset
-    _cs = 1;
-    _rst = 0;
-    _spi.format(9);
-    _spi.frequency(NOKIALCD_FREQUENCY);
-    wait_ms(1);
-    _rst = 1;
-    wait_ms(1);
-
-    _cs = 0;
-
-    switch (_type) {
-        case LCD6100:
-            command(0xCA); // display control
-            data(0);
-            data(32);
-            data(0);
-            command(0xBB);
-            data(1);
-            command(0xD1); // oscillator on
-            command(0x94); // sleep out
-            command(0x20); // power control
-            data(0x0F);
-            command(0xA7); // invert display
-            command(0x81); // Voltage control
-            data(39);      // contrast setting: 0..63
-            data(3);       // resistance ratio
-            wait_ms(1);
-            command(0xBC);
-            data(0);
-            data(1);
-            data(4);
-            command(0xAF);  // turn on the display
-            break;
-            
-        case LCD6610:
-            command(0xCA);    // display control
-            data(0);
-            data(31);
-            data(0);
-            command(0xBB);
-            data(1);
-            command(0xD1); // oscillator on
-            command(0x94); // sleep out
-            command(0x20); // power control
-            data(0x0F);
-            command(0xA7); // invert display
-            command(0x81); // Voltage control
-            data(39);      // contrast setting: 0..63
-            data(3);       // resistance ratio
-            wait_ms(1);
-            command(0xBC);
-            data(0);
-            data(0);
-            data(2);
-            command(0xAF);  // turn on the display
-            break;
-            
-        case PCF8833:
-            command(0x11);  // sleep out
-            command(0x3A);  // column mode
-            data(0x05);
-            command(0x36);  // madctl
-            data(0x60);     // vertical RAM, flip x
-            command(0x25);  // setcon
-            data(0x30);// contrast 0x30
-            wait_ms(2);
-            command(0x29);//DISPON
-            command(0x03);//BSTRON
-            break;
-    }
-
-    _cs = 1;
-
-    cls();
-}
-
-void NokiaLCD::command(int value) {
-    _spi.write(value & 0xFF);
-}
-
-void NokiaLCD::data(int value) {
-    _spi.write(value | 0x100);
-}
-
-void NokiaLCD::_window(int x, int y, int width, int height) {
-    int x1 = x + 2;
-    int y1 = y + 0;
-    int x2 = x1 + width - 1;
-    int y2 = y1 + height - 1;
-
-    switch (_type) {
-        case LCD6100:
-        case LCD6610:
-            command(0x15); // column
-            data(x1);
-            data(x2);
-            command(0x75); // row
-            data(y1);
-            data(y2);
-            command(0x5C); // start write to ram
-            break;
-        case PCF8833:
-            command(0x2A);  // column
-            data(x1);
-            data(x2);
-            command(0x2B); // row
-            data(y1);
-            data(y2);
-            command(0x2C); // start write to ram
-            break;
-    }
-}
-
-void NokiaLCD::_putp(int colour) {
-    int gr = ((colour >> 20) & 0x0F)
-             | ((colour >> 8 ) & 0xF0);
-    int nb = ((colour >> 4 ) & 0x0F);
-    data(nb);
-    data(gr);
-}
-
-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
-
-void NokiaLCD::locate(int column, int row) {
-    _column = column;
-    _row = row;
-}
-
-void NokiaLCD::newline() {
-    _column = 0;
-    _row++;
-    if (_row >= _rows) {
-        _row = 0;
-    }
-}
-
-int NokiaLCD::_putc(int value) {
-    int x = _column * 8;  // FIXME: Char sizes
-    int y = _row * 8;
-    bitblit(x + 1, y + 1, 8, 8, (char*)&(FONT8x8[value - 0x1F][0]));
-
-    _column++;
-
-    if (_column >= NOKIALCD_COLS) {
-        _row++;
-        _column = 0;
-    }
-
-    if (_row >= NOKIALCD_ROWS) {
-        _row = 0;
-    }
-
-    return value;
-}
-
-void NokiaLCD::cls() {
-    fill(0, 0, NOKIALCD_WIDTH, NOKIALCD_HEIGHT, _background);
-    _row = 0;
-    _column = 0;
-}
-
-
-void NokiaLCD::window(int x, int y, int width, int height) {
-    _cs = 0;
-    _window(x, y, width, height);
-    _cs = 1;
-}
-
-void NokiaLCD::putp(int colour) {
-    _cs = 0;
-    _putp(colour);
-    _cs = 1;
-}
-
-void NokiaLCD::pixel(int x, int y, int colour) {
-    _cs = 0;
-    _window(x, y, 1, 1);
-    _putp(colour);
-    _cs = 1;
-}
-
-void NokiaLCD::fill(int x, int y, int width, int height, int colour) {
-    _cs = 0;
-    _window(x, y, width, height);
-    switch (_type) {
-        case LCD6100:
-        case PCF8833:
-            for (int i=0; i<width*height; i++) {
-                _putp(colour);
-            }
-            break;
-        case LCD6610:
-            for (int i=0; i<width*height/2; i++) {
-                int r4 = (colour >> (16 + 4)) & 0xF;
-    	        int g4 = (colour >> (8 + 4)) & 0xF;
-                int b4 = (colour >> (0 + 4)) & 0xF;
-        	    int d1 = (r4 << 4) | g4;
-                int d2 = (b4 << 4) | r4;
-                int d3 = (g4 << 4) | b4;
-                data(d1); 
-    	        data(d2);   
-    	        data(d3);
-            }
-            break;
-    }
-    _window(0, 0, NOKIALCD_WIDTH, NOKIALCD_HEIGHT);
-    _cs = 1;
-}
-
-void NokiaLCD::blit(int x, int y, int width, int height, const int* colour) {
-    _cs = 0;
-    _window(x, y, width, height);
-
-    switch (_type) {
-        case LCD6100:
-        case PCF8833:
-            for (int i=0; i<width*height; i++) {
-                 _putp(colour[i]);
-             }
-             break;
-        case LCD6610:
-            for (int i=0; i<width*height/2; i++) {
-        	    int r41 = (colour[i*2] >> (16 + 4)) & 0xF;
-        	    int g41 = (colour[i*2] >> (8 + 4)) & 0xF;
-        	    int b41 = (colour[i*2] >> (0 + 4)) & 0xF;
-    	   
-                int r42 = (colour[i*2+1] >> (16 + 4)) & 0xF;
-        	    int g42 = (colour[i*2+1] >> (8 + 4)) & 0xF;
-        	    int b42 = (colour[i*2+1] >> (0 + 4)) & 0xF;   
-        	    int d1 = (r41 << 4) | g41;
-        	    int d2 = (b41 << 4) | r42;
-        	    int d3 = (g42 << 4) | b42;               
-       	        data(d1); 
-    	        data(d2); 
-    	        data(d3); 
-            }
-            break;
-     }            
-    _window(0, 0, NOKIALCD_WIDTH, NOKIALCD_HEIGHT);
-    _cs = 1;
-}
-
-void NokiaLCD::bitblit(int x, int y, int width, int height, const char* bitstream) {
-    _cs = 0;
-    _window(x, y, width, height);
-
-    switch (_type) {
-        case LCD6100:
-        case PCF8833:
-            for (int i=0; i<height*width; i++) {
-                int byte = i / 8;
-                int bit = i % 8;
-                int colour = ((bitstream[byte] << bit) & 0x80) ? _foreground : _background;
-                _putp(colour);
-            }
-            break;
-        case LCD6610:
-            for(int i=0; i<height*width/2; i++) {
-                int byte1 = (i*2) / 8;
-                int bit1 = (i*2) % 8;   
-        	    int colour1 = ((bitstream[byte1] << bit1) & 0x80) ? _foreground : _background;
-        	    int byte2 = (i*2+1) / 8;
-                int bit2 = (i*2+1) % 8;   
-                int colour2 = ((bitstream[byte2] << bit2) & 0x80) ? _foreground : _background;
-	
-        	    int r41 = (colour1 >> (16 + 4)) & 0xF;
-        	    int g41 = (colour1 >> (8 + 4)) & 0xF;
-        	    int b41 = (colour1 >> (0 + 4)) & 0xF;
-    	   
-                int r42 = (colour2 >> (16 + 4)) & 0xF;
-        	    int g42 = (colour2 >> (8 + 4)) & 0xF;
-        	    int b42 = (colour2 >> (0 + 4)) & 0xF;   
-        	    int d1 = (r41 << 4) | g41;
-        	    int d2 = (b41 << 4) | r42;
-        	    int d3 = (g42 << 4) | b42;               
-       	        data(d1); 
-    	        data(d2); 
-    	        data(d3); 
-            }
-            break;
-     }
-    _window(0, 0, _width, _height);
-    _cs = 1;
-}
-
-void NokiaLCD::foreground(int c) {
-    _foreground = c;
-}
-
-void NokiaLCD::background(int c) {
-    _background = c;
-}
-
-int NokiaLCD::width() {
-    return NOKIALCD_WIDTH;
-}
-
-int NokiaLCD::height() {
-    return NOKIALCD_HEIGHT;
-}
-
-int NokiaLCD::columns() {
-    return NOKIALCD_COLS;
-}
-
-int NokiaLCD::rows() {
-    return NOKIALCD_ROWS;
-}
+/* mbed Nokia LCD Library
+ * Copyright (c) 2007-2010, sford
+ */
+
+#include "NokiaLCD.h"
+
+#include "mbed.h"
+
+#define NOKIALCD_ROWS 16
+#define NOKIALCD_COLS 16
+#define NOKIALCD_WIDTH 130
+#define NOKIALCD_HEIGHT 130
+#define NOKIALCD_FREQUENCY 5000000
+
+NokiaLCD::NokiaLCD(PinName mosi, PinName sclk, PinName cs, PinName rst, LCDType type)
+        : _spi(mosi, NC, sclk)
+        , _rst(rst)
+        , _cs(cs) {
+
+    _type = type;
+
+    _row = 0;
+    _column = 0;
+    _foreground = 0x00FFFFFF;
+    _background = 0x00000000;
+
+    reset();
+}
+
+void NokiaLCD::reset() {
+
+    // setup the SPI interface and bring display out of reset
+    _cs = 1;
+    _rst = 0;
+    _spi.format(9);
+    _spi.frequency(NOKIALCD_FREQUENCY);
+    wait_ms(1);
+    _rst = 1;
+    wait_ms(1);
+
+    _cs = 0;
+
+    switch (_type) {
+        case LCD6100:
+            command(0xCA); // display control
+            data(0);
+            data(32);
+            data(0);
+            command(0xBB);
+            data(1);
+            command(0xD1); // oscillator on
+            command(0x94); // sleep out
+            command(0x20); // power control
+            data(0x0F);
+            command(0xA7); // invert display
+            command(0x81); // Voltage control
+            data(39);      // contrast setting: 0..63
+            data(3);       // resistance ratio
+            wait_ms(1);
+            command(0xBC);
+            data(0);
+            data(1);
+            data(4);
+            command(0xAF);  // turn on the display
+            break;
+            
+        case LCD6610:
+            command(0xCA);    // display control
+            data(0);
+            data(31);
+            data(0);
+            command(0xBB);
+            data(1);
+            command(0xD1); // oscillator on
+            command(0x94); // sleep out
+            command(0x20); // power control
+            data(0x0F);
+            command(0xA7); // invert display
+            command(0x81); // Voltage control
+            data(39);      // contrast setting: 0..63
+            data(3);       // resistance ratio
+            wait_ms(1);
+            command(0xBC);
+            data(0);
+            data(0);
+            data(2);
+            command(0xAF);  // turn on the display
+            break;
+            
+        case PCF8833:
+            command(0x11);  // sleep out
+            command(0x3A);  // column mode
+            data(0x05);
+            command(0x36);  // madctl
+            data(0x60);     // vertical RAM, flip x
+            command(0x25);  // setcon
+            data(0x30);// contrast 0x30
+            wait_ms(2);
+            command(0x29);//DISPON
+            command(0x03);//BSTRON
+            break;
+    }
+
+    _cs = 1;
+
+    cls();
+}
+
+void NokiaLCD::command(int value) {
+    _spi.write(value & 0xFF);
+}
+
+void NokiaLCD::data(int value) {
+    _spi.write(value | 0x100);
+}
+
+void NokiaLCD::_window(int x, int y, int width, int height) {
+    int x1 = x + 0;
+    int y1 = y + 0;
+    int x2 = x1 + width - 1;
+    int y2 = y1 + height - 1;
+
+    switch (_type) {
+        case LCD6100:
+        case LCD6610:
+            command(0x15); // column
+            data(x1);
+            data(x2);
+            command(0x75); // row
+            data(y1);
+            data(y2);
+            command(0x5C); // start write to ram
+            break;
+        case PCF8833:
+            command(0x2A);  // column
+            data(x1);
+            data(x2);
+            command(0x2B); // row
+            data(y1);
+            data(y2);
+            command(0x2C); // start write to ram
+            break;
+    }
+}
+
+void NokiaLCD::_putp(int colour) {
+    int gr = ((colour >> 20) & 0x0F)
+             | ((colour >> 8 ) & 0xF0);
+    int nb = ((colour >> 4 ) & 0x0F);
+    data(nb);
+    data(gr);
+}
+
+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
+
+void NokiaLCD::locate(int column, int row) {
+    _column = column;
+    _row = row;
+}
+
+void NokiaLCD::newline() {
+    _column = 0;
+    _row++;
+    if (_row >= _rows) {
+        _row = 0;
+    }
+}
+
+int NokiaLCD::_putc(int value) {
+    int x = _column * 8;  // FIXME: Char sizes
+    int y = _row * 8;
+    bitblit(x + 1, y + 1, 8, 8, (char*)&(FONT8x8[value - 0x1F][0]));
+
+    _column++;
+
+    if (_column >= NOKIALCD_COLS) {
+        _row++;
+        _column = 0;
+    }
+
+    if (_row >= NOKIALCD_ROWS) {
+        _row = 0;
+    }
+
+    return value;
+}
+
+void NokiaLCD::cls() {
+    fill(0, 0, NOKIALCD_WIDTH, NOKIALCD_HEIGHT, _background);
+    _row = 0;
+    _column = 0;
+}
+
+
+void NokiaLCD::window(int x, int y, int width, int height) {
+    _cs = 0;
+    _window(x, y, width, height);
+    _cs = 1;
+}
+
+void NokiaLCD::putp(int colour) {
+    _cs = 0;
+    _putp(colour);
+    _cs = 1;
+}
+
+void NokiaLCD::pixel(int x, int y, int colour) {
+    _cs = 0;
+    _window(x, y, 1, 1);
+    switch (_type) {
+        case LCD6100:
+        case PCF8833:
+            
+                _putp(colour);
+             
+            break;
+        case LCD6610:
+            
+                int r4 = (colour >> (16 + 4)) & 0xF;
+                int g4 = (colour >> (8 + 4)) & 0xF;
+                int b4 = (colour >> (0 + 4)) & 0xF;
+                int d1 = (r4 << 4) | g4;
+                int d2 = (b4 << 4) | r4;
+                int d3 = (g4 << 4) | b4;
+                data(d1); 
+                data(d2);   
+                data(d3);
+             
+            break;
+    }
+    _cs = 1;
+}
+
+void NokiaLCD::fill(int x, int y, int width, int height, int colour) {
+    _cs = 0;
+    _window(x, y, width, height);
+    switch (_type) {
+        case LCD6100:
+        case PCF8833:
+            for (int i=0; i<width*height; i++) {
+                _putp(colour);
+            }
+            break;
+        case LCD6610:
+            for (int i=0; i<width*height/2; i++) {
+                int r4 = (colour >> (16 + 4)) & 0xF;
+                int g4 = (colour >> (8 + 4)) & 0xF;
+                int b4 = (colour >> (0 + 4)) & 0xF;
+                int d1 = (r4 << 4) | g4;
+                int d2 = (b4 << 4) | r4;
+                int d3 = (g4 << 4) | b4;
+                data(d1); 
+                data(d2);   
+                data(d3);
+            }
+            break;
+    }
+    _window(0, 0, NOKIALCD_WIDTH, NOKIALCD_HEIGHT);
+    _cs = 1;
+}
+
+void NokiaLCD::blit(int x, int y, int width, int height, const int* colour) {
+    _cs = 0;
+    _window(x, y, width, height);
+
+    switch (_type) {
+        case LCD6100:
+        case PCF8833:
+            for (int i=0; i<width*height; i++) {
+                 _putp(colour[i]);
+             }
+             break;
+        case LCD6610:
+            for (int i=0; i<width*height/2; i++) {
+                int r41 = (colour[i*2] >> (16 + 4)) & 0xF;
+                int g41 = (colour[i*2] >> (8 + 4)) & 0xF;
+                int b41 = (colour[i*2] >> (0 + 4)) & 0xF;
+           
+                int r42 = (colour[i*2+1] >> (16 + 4)) & 0xF;
+                int g42 = (colour[i*2+1] >> (8 + 4)) & 0xF;
+                int b42 = (colour[i*2+1] >> (0 + 4)) & 0xF;   
+                int d1 = (r41 << 4) | g41;
+                int d2 = (b41 << 4) | r42;
+                int d3 = (g42 << 4) | b42;               
+                   data(d1); 
+                data(d2); 
+                data(d3); 
+            }
+            break;
+     }            
+    _window(0, 0, NOKIALCD_WIDTH, NOKIALCD_HEIGHT);
+    _cs = 1;
+}
+
+void NokiaLCD::bitblit(int x, int y, int width, int height, const char* bitstream) {
+    _cs = 0;
+    _window(x, y, width, height);
+
+    switch (_type) {
+        case LCD6100:
+        case PCF8833:
+            for (int i=0; i<height*width; i++) {
+                int byte = i / 8;
+                int bit = i % 8;
+                int colour = ((bitstream[byte] << bit) & 0x80) ? _foreground : _background;
+                _putp(colour);
+            }
+            break;
+        case LCD6610:
+            for(int i=0; i<height*width/2; i++) {
+                int byte1 = (i*2) / 8;
+                int bit1 = (i*2) % 8;   
+                int colour1 = ((bitstream[byte1] << bit1) & 0x80) ? _foreground : _background;
+                int byte2 = (i*2+1) / 8;
+                int bit2 = (i*2+1) % 8;   
+                int colour2 = ((bitstream[byte2] << bit2) & 0x80) ? _foreground : _background;
+    
+                int r41 = (colour1 >> (16 + 4)) & 0xF;
+                int g41 = (colour1 >> (8 + 4)) & 0xF;
+                int b41 = (colour1 >> (0 + 4)) & 0xF;
+           
+                int r42 = (colour2 >> (16 + 4)) & 0xF;
+                int g42 = (colour2 >> (8 + 4)) & 0xF;
+                int b42 = (colour2 >> (0 + 4)) & 0xF;   
+                int d1 = (r41 << 4) | g41;
+                int d2 = (b41 << 4) | r42;
+                int d3 = (g42 << 4) | b42;               
+                   data(d1); 
+                data(d2); 
+                data(d3); 
+            }
+            break;
+     }
+    _window(0, 0, _width, _height);
+    _cs = 1;
+}
+
+void NokiaLCD::foreground(int c) {
+    _foreground = c;
+}
+
+void NokiaLCD::background(int c) {
+    _background = c;
+}
+
+int NokiaLCD::width() {
+    return NOKIALCD_WIDTH;
+}
+
+int NokiaLCD::height() {
+    return NOKIALCD_HEIGHT;
+}
+
+int NokiaLCD::columns() {
+    return NOKIALCD_COLS;
+}
+
+int NokiaLCD::rows() {
+    return NOKIALCD_ROWS;
+}