Added circle and line support

NokiaLCD.cpp

Committer:
Lerche
Date:
2010-10-07
Revision:
4:92ccde806538
Parent:
2:d99e9681356b

File content as of revision 4:92ccde806538:

/* 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);
    for (int i=0; i<width*height; i++) {
        _putp(colour);
    }
    _window(0, 0, NOKIALCD_WIDTH, NOKIALCD_HEIGHT);
    _cs = 1;
}

void NokiaLCD::circle(int x0, int y0, int r, int colour) {
    int draw_x0, draw_y0;
    int draw_x1, draw_y1;
    int draw_x2, draw_y2;
    int draw_x3, draw_y3;
    int draw_x4, draw_y4;
    int draw_x5, draw_y5;
    int draw_x6, draw_y6;
    int draw_x7, draw_y7;
    int xx, yy;
    int di;    

    _cs = 0;
    _window(x0, y0, 1, 1);

    if(r == 0)          /* no radius */
    {
        return;
    }

    draw_x0 = draw_x1 = x0;
    draw_y0 = draw_y1 = y0 + r;
    if(draw_y0 < NOKIALCD_HEIGHT)
    {
        _window(draw_x0, draw_y0, 1, 1);
        _putp(colour);     /* 90 degree */
    }

    draw_x2 = draw_x3 = x0;
    draw_y2 = draw_y3 = y0 - r;
    if(draw_y2 >= 0)
    {
        _window(draw_x2, draw_y2, 1, 1);
        _putp(colour);    /* 270 degree */
    }
    
    draw_x4 = draw_x6 = x0 + r;
    draw_y4 = draw_y6 = y0;
    if(draw_x4 < NOKIALCD_WIDTH)
    {
        _window(draw_x4, draw_y4, 1, 1);
        _putp(colour);     /* 0 degree */
    }    
    
    draw_x5 = draw_x7 = x0 - r;
    draw_y5 = draw_y7 = y0;
    if(draw_x5>=0)
    {
        _window(draw_x5, draw_y5, 1, 1);
        _putp(colour);     /* 90 degree */     /* 180 degree */
    }
        
    if(r == 1)
    {
        return;
    }    
    
    di = 3 - 2*r;
    xx = 0;
    yy = r;
    while(xx < yy)
    {

        if(di < 0)
        {
            di += 4*xx + 6;
        }
        else
        {
            di += 4*(xx - yy) + 10;
            yy--;
            draw_y0--;
            draw_y1--;
            draw_y2++;
            draw_y3++;
            draw_x4--;
            draw_x5++;
            draw_x6--;
            draw_x7++;
        }
        xx++;
        draw_x0++;
        draw_x1--;
        draw_x2++;
        draw_x3--;
        draw_y4++;
        draw_y5++;
        draw_y6--;
        draw_y7--;

        if( (draw_x0 <= NOKIALCD_WIDTH) && (draw_y0>=0) )
        {
            _window(draw_x0, draw_y0, 1, 1);
            _putp(colour);
        }

        if( (draw_x1 >= 0) && (draw_y1 >= 0) )
        {
            _window(draw_x1, draw_y1, 1, 1);
            _putp(colour);
        }

        if( (draw_x2 <= NOKIALCD_WIDTH) && (draw_y2 <= NOKIALCD_HEIGHT) )
        {
            _window(draw_x2, draw_y2, 1, 1);
            _putp(colour);
        }

        if( (draw_x3 >=0 ) && (draw_y3 <= NOKIALCD_HEIGHT) )
        {
            _window(draw_x3, draw_y3, 1, 1);
            _putp(colour);
        }

        if( (draw_x4 <= /*OLED_DISPLAY_HEIGHT*/NOKIALCD_WIDTH) && (draw_y4 >= 0) )
        {
            _window(draw_x4, draw_y4, 1, 1);
            _putp(colour);
        }

        if( (draw_x5 >= 0) && (draw_y5 >= 0) )
        {
            _window(draw_x5, draw_y5, 1, 1);
            _putp(colour);
        }
        if( (draw_x6 <= NOKIALCD_WIDTH) && (draw_y6 <= NOKIALCD_HEIGHT) )
        {
            _window(draw_x6, draw_y6, 1, 1);
            _putp(colour);
        }
        if( (draw_x7 >= 0) && (draw_y7 <= NOKIALCD_HEIGHT) )
        {
            _window(draw_x7, draw_y7, 1, 1);
            _putp(colour);
        }
    }
    _cs = 1;
    return;
}

void NokiaLCD::line(int x0, int y0, int x1, int y1, int colour) {
    int   dx = 0, dy = 0;
    int   dx_sym = 0, dy_sym = 0;
    int   dx_x2 = 0, dy_x2 = 0;
    int   di = 0;

    _cs = 0;            // Chipselect the LCD. 

    dx = x1-x0;
    dy = y1-y0;


    if(dx == 0)           /* vertical line */
    {
        for(int y=y0; y<y1; y++){
            _window(x0, y, 1, 1);
            _putp(colour);
        }
        return;
    }

    if(dx > 0)
    {
        dx_sym = 1;
    }
    else
    {
        dx_sym = -1;
    }


    if(dy == 0)           /* horizontal line */
    {
        for(int x=x0; x<x1; x++){
            _window(x, y0, 1, 1);
            _putp(colour);
        }
        return;
    }


    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)
        {

            _window(x0, y0, 1, 1);
            _putp(colour);
            x0 += dx_sym;
            if(di<0)
            {
                di += dy_x2;
            }
            else
            {
                di += dy_x2 - dx_x2;
                y0 += dy_sym;
            }
        }
        _window(x0, y0, 1, 1);
        _putp(colour);
    }
    else
    {
        di = dx_x2 - dy;
        while(y0 != y1)
        {
            _window(x0, y0, 1, 1);
            _putp(colour);
            y0 += dy_sym;
            if(di < 0)
            {
                di += dx_x2;
            }
            else
            {
                di += dx_x2 - dy_x2;
                x0 += dx_sym;
            }
        }
        _window(x0, y0, 1, 1);
        _putp(colour);
    }
    _cs = 1;
    return;
}

void NokiaLCD::blit(int x, int y, int width, int height, const int* colour) {
    _cs = 0;
    _window(x, y, width, height);
    for (int i=0; i<width*height; i++) {
        _putp(colour[i]);
    }
    _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);
    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);
    }
    _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;
}