Library for Nuelectronics Nokia 3310/5110 LCD Display and joystick.

Dependents:   LEDFun NetTester

Fork of N3310LCD by Andrew Lindsay

Library for Nuelectronics Nokia 3310/5110 LCD Display and joystick.

N3310LCD.cpp

Committer:
SomeRandomBloke
Date:
2013-03-10
Revision:
1:51961974fe55
Parent:
0:7efa6655d94b
Child:
3:9808f63fd2fe

File content as of revision 1:51961974fe55:

/*
* N3310LCD. A program to interface mbed with the nuelectronics
* Nokia 3310 LCD shield from www.nuelectronics.com. Ported from
* the nuelectronics Arduino code.
*
* Copyright (C) <2009> Petras Saduikis <petras@petras.co.uk>
*
* Converted to a mbed library by Andrew D. Lindsay
*
* This file is part of N3310LCD.
*
* N3310LCD is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* N3310LCD is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with N3310LCD.  If not, see <http://www.gnu.org/licenses/>.
*/

#include "N3310LCD.h"
#include "N3310Fonts.h"

static unsigned char lcd_buffer[LCDROWMAX][LCDCOLMAX];

N3310LCD::N3310LCD (PinName mosi, PinName miso, PinName sck,
                    PinName ce, PinName dat_cmd, PinName lcd_rst, PinName bl_on) :
    lcdPort(mosi, miso, sck),
    ceWire(ce), dcWire(dat_cmd), rstWire(lcd_rst), blWire(bl_on)
{
}

void N3310LCD::init()
{
    // use default SPI format
    lcdPort.format(8,0);
    lcdPort.frequency(1000000);

    // lcd reset
    wait_ms(1);
    rstWire = 0;
    wait_ms(1);
    rstWire = 1;

    write(0x21, CMD);
    write(0xc8, CMD);
    write(0x06, CMD);
    write(0x13, CMD);
    write(0x20, CMD);
    cls();
    write(0x0c, CMD);
}

void N3310LCD::cls()
{
    write(0x0c, CMD);
    write(0x80, CMD);

    for (int i = 0; i < 504; i++) {
        write(0, DATA);
    }
}

void N3310LCD::backlight(eBacklight state)
{
    // switch off/on back light
    blWire = state;
}

void N3310LCD::write(BYTE data, eRequestType req_type)
{
    // bring CS low for write
    ceWire = 0;

    if (CMD == req_type)
        dcWire = 0;
    else // DATA
        dcWire = 1;

    lcdPort.write(data);

    // write finished
    ceWire = 1;
}

void N3310LCD::locate(BYTE xPos, BYTE yPos)
{
    write(0x40 | yPos, CMD);      // column
    write(0x80 | xPos, CMD);      // row
}

void N3310LCD::drawBitmap(BYTE xPos, BYTE yPos, BYTE* bitmap, BYTE bmpXSize, BYTE bmpYSize)
{
    BYTE row;

    if (0 == bmpYSize % 8)
        row = bmpYSize/8;
    else
        row = bmpYSize/8 + 1;

    for (BYTE n = 0; n < row; n++) {
        locate(xPos, yPos);
        for(BYTE i = 0; i < bmpXSize; i++) {
            write(bitmap[i + (n * bmpXSize)], DATA);
        }
        yPos++;
    }
}

/*
 * Name         : clearBitmap
 * Description  : Clear an area of the screen, usually to blank out a
 *        previously drawn image or part of image.
 * Argument(s)  : x, y - Position on screen, x 0-83, y 1-6
 *                size_x,size_y - Size of the image in pixels,
 *                size_y is multiple of 8
 * Return value : none
 */
void N3310LCD::clearBitmap( unsigned char x,unsigned char y,
                            unsigned char size_x,unsigned char size_y)
{
    unsigned int i,n;
    unsigned char row;

    row = (size_y % 8 == 0 ) ? size_y / 8 : size_y / 8 + 1;
//    if (size_y % 8==0)
//      row=size_y/8;
//    else
//          row=size_y/8+1;

    for (n=0; n<row; n++) {
        locate(x,y);
        for(i=0; i<size_x; i++) {
            write( 0x00, DATA );
        }
        y++;
    }
}

void N3310LCD::writeString(BYTE xPos, BYTE yPos, char* string, eDisplayMode mode)
{
    locate(xPos, yPos);

    while (*string) {
        writeChar(*string++, mode);
    }
}

void N3310LCD::writeStringBig(BYTE xPos, BYTE yPos, char* string, eDisplayMode mode)
{
    while (*string) {
        writeCharBig(xPos, yPos, *string , mode);

        if('.' == *string++)
            xPos += 5;
        else
            xPos += 12;
    }
}

void N3310LCD::writeChar(BYTE ch, eDisplayMode mode)
{
    BYTE sendByte;

    unsigned char* pFont = (unsigned char*)font6_8;
    ch -= 32;

    for (BYTE line = 0; line < 6; line++) {
        sendByte = *(pFont + ch*6 + line);
        write((mode == NORMAL)? sendByte: (sendByte ^ 0xff) , DATA);
    }
}

void N3310LCD::writeCharBig(BYTE xPos, BYTE yPos, BYTE ch, eDisplayMode mode)
{
    BYTE sendByte;

    unsigned char* pFont = (unsigned char *) big_number;

    if('.' == ch)
        ch = 10;
    else if ('+' == ch)
        ch = 11;
    else if ('-' == ch)
        ch = 12;
    else
        ch = ch & 0x0f;

    for(BYTE i = 0; i < 3; i++) {
        locate(xPos, yPos + i);

        for(BYTE j = 0; j < 16; j++) {
            sendByte =  *(pFont + ch*48 + i*16 + j);
            write((mode == NORMAL)? sendByte : (sendByte^0xff), DATA);
        }
    }
}

/*
 * Name         : setPixel
 * Description  : Set a single pixel either on or off, update display buffer.
 * Argument(s)  : x,y - position, x = 0-83, y = 0-6
 *                c - colour, either PIXEL_ON, PIXEL_OFF or PIXEL_XOR
 * Return value : none
 */
void N3310LCD::setPixel( unsigned char x, unsigned char y, unsigned char c )
{
    unsigned char value;
    unsigned char row;

//    if( x < 0 || x >= LCDCOLMAX || y < 0 || y >= LCDPIXELROWMAX ) return;
    if( x >= LCDCOLMAX || y >= LCDPIXELROWMAX ) return;

    row = y / 8;

    value = lcd_buffer[row][x];
    if( c == PIXEL_ON ) {
        value |= (1 << (y % 8));
    } else if( c == PIXEL_XOR ) {
        value ^= (1 << (y % 8));
    } else {
        value &= ~(1 << (y % 8));
    }

    lcd_buffer[row][x] = value;

    locate (x,row);
    write(value, DATA);
}


/*
 * Name         : drawLine
 * Description  : Draws a line between two points on the display.
 * Argument(s)  : x1, y1 - Absolute pixel coordinates for line origin.
 *                x2, y2 - Absolute pixel coordinates for line end.
 *                c - either PIXEL_ON, PIXEL_OFF or PIXEL_XOR
 * Return value : none
 */
void N3310LCD::drawLine(unsigned char x1, unsigned char y1,
                        unsigned char x2, unsigned char y2, unsigned char c)
{
    int dx, dy, stepx, stepy, fraction;

    /* Calculate differential form */
    /* dy   y2 - y1 */
    /* -- = ------- */
    /* dx   x2 - x1 */

    /* Take differences */
    dy = y2 - y1;
    dx = x2 - x1;

    /* dy is negative */
    if ( dy < 0 ) {
        dy    = -dy;
        stepy = -1;
    } else {
        stepy = 1;
    }

    /* dx is negative */
    if ( dx < 0 ) {
        dx    = -dx;
        stepx = -1;
    } else {
        stepx = 1;
    }

    dx <<= 1;
    dy <<= 1;

    /* Draw initial position */
    setPixel( x1, y1, c );

    /* Draw next positions until end */
    if ( dx > dy ) {
        /* Take fraction */
        fraction = dy - ( dx >> 1);
        while ( x1 != x2 ) {
            if ( fraction >= 0 ) {
                y1 += stepy;
                fraction -= dx;
            }
            x1 += stepx;
            fraction += dy;

            /* Draw calculated point */
            setPixel( x1, y1, c );
        }
    } else {
        /* Take fraction */
        fraction = dx - ( dy >> 1);
        while ( y1 != y2 ) {
            if ( fraction >= 0 ) {
                x1 += stepx;
                fraction -= dy;
            }
            y1 += stepy;
            fraction += dx;

            /* Draw calculated point */
            setPixel( x1, y1, c );
        }
    }
}


/*
 * Name         : drawRectangle
 * Description  : Draw a rectangle given to top left and bottom right points
 * Argument(s)  : x1, y1 - Absolute pixel coordinates for top left corner
 *                x2, y2 - Absolute pixel coordinates for bottom right corner
 *                c - either PIXEL_ON, PIXEL_OFF or PIXEL_XOR
 * Return value : none
 */
void N3310LCD::drawRectangle(unsigned char x1, unsigned char y1,
                             unsigned char x2, unsigned char y2, unsigned char c)
{
    drawLine( x1, y1, x2, y1, c );
    drawLine( x1, y1, x1, y2, c );
    drawLine( x1, y2, x2, y2, c );
    drawLine( x2, y1, x2, y2, c );
}


/*
 * Name         : drawFilledRectangle
 * Description  : Draw a filled rectangle given to top left and bottom right points
 *        just simply draws horizontal lines where the rectangle would be
 * Argument(s)  : x1, y1 - Absolute pixel coordinates for top left corner
 *                x2, y2 - Absolute pixel coordinates for bottom right corner
 *                c - either PIXEL_ON, PIXEL_OFF or PIXEL_XOR
 * Return value : none
 */
void N3310LCD::drawFilledRectangle(unsigned char x1, unsigned char y1,
                                   unsigned char x2, unsigned char y2, unsigned char c)
{
    for(int i=y1; i <= y2; i++ ) {
        drawLine( x1, i, x2, i, c );
    }
}


/*
 * Name         : drawCircle
 * Description  : Draw a circle using Bresenham's algorithm.
 *        Some small circles will look like squares!!
 * Argument(s)  : xc, yc - Centre of circle
 *        r - Radius
 *        c - either PIXEL_ON, PIXEL_OFF or PIXEL_XOR
 * Return value : None
 */
void N3310LCD::drawCircle(unsigned char xc, unsigned char yc,
                          unsigned char r, unsigned char c)
{
    int x=0;
    int y=r;
    int p=3-(2*r);

    setPixel( (uint8_t)(xc+x),(uint8_t)(yc-y), c);

    for(x=0; x<=y; x++) {
        if (p<0) {
            y=y;
            p=(p+(4*x)+6);
        } else {
            y=y-1;
            p=p+((4*(x-y)+10));
        }

        setPixel((uint8_t)(xc+x),(uint8_t)(yc-y), c);
        setPixel((uint8_t)(xc-x),(uint8_t)(yc-y), c);
        setPixel((uint8_t)(xc+x),(uint8_t)(yc+y), c);
        setPixel((uint8_t)(xc-x),(uint8_t)(yc+y), c);
        setPixel((uint8_t)(xc+y),(uint8_t)(yc-x), c);
        setPixel((uint8_t)(xc-y),(uint8_t)(yc-x), c);
        setPixel((uint8_t)(xc+y),(uint8_t)(yc+x), c);
        setPixel((uint8_t)(xc-y),(uint8_t)(yc+x), c);
    }
}