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-27
Revision:
5:1fd7af32e521
Parent:
4:90dce6032a37
Child:
6:46bcc4e584c4

File content as of revision 5:1fd7af32e521:

/*
* 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];
// current cursor postition
static unsigned char cursor_row = 0; /* 0-5 */
static unsigned char cursor_col = 0; /* 0-83 */
unsigned char *fontStart;  // Start of font data
int8_t fontWidth;       // Font width
int8_t fontHeight;      // Font height
int16_t fontStartChar;   // Start, usually 32
int16_t fontEndChar;     // End character, usually 127 or 128

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(8000000);     // Lets try 8MHz

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

    writeCommand(0x21);     // LCD Extended Commands
    writeCommand(0xC0);     // Set LCD Vop (Contrast)
    writeCommand(0x06);     // Set temp coefficient
    writeCommand(0x13);     // LCD bias mode1:48
    writeCommand(0x20);     // LCD Standard Commands, Horizontal addressing mode
    writeCommand(0x0c);     // LCD in normal mode
    cls();
    setFont( FONT_5x7 );
//    setFont( FONT_6x8 );

}

void N3310LCD::setFont(BYTE font )
{

    switch( font ) {
        case FONT_6x8:
            fontWidth = 6;
            fontHeight = 8;
            fontStartChar = 32;
            fontEndChar = 128;
            fontStart = font6_8;
            break;
            
 /*       case FONT_ALPHA_17x17:
            fontWidth = 17;
            fontHeight = 17;
            fontStartChar = 65;
            fontEndChar = 91;
            fontStart = Liberation_Sans17x17_Alpha;
            break;
*/
        default:
            fontWidth = 5;
            fontHeight = 7;
            fontStartChar = 32;
            fontEndChar = 128;
            fontStart = font5_7;
            break;
    }
}

void N3310LCD::cls()
{
    writeCommand(0x40);      // column
    writeCommand(0x80);      // row
    for(int i=0; i< LCDROWMAX; i++) {
        for(int j=0; j< LCDCOLMAX; j++) {
            writeData( 0x00 );
            lcd_buffer[i][j] = 0x00;
        }
    }
}

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

void N3310LCD::writeCommand(BYTE data)
{
    // bring CS low for write
    ceWire = 0;
    dcWire = 0;

    lcdPort.write(data);

    // write finished
    ceWire = 1;
}

void N3310LCD::writeData(BYTE data)
{
    // bring CS low for write
    ceWire = 0;
    dcWire = 1;

    lcdPort.write(data);

    // write finished
    ceWire = 1;
}

void N3310LCD::locate(BYTE xPos, BYTE yPos)
{
    writeCommand(0x40 | yPos);      // column
    writeCommand(0x80 | xPos);      // row
    cursor_row = yPos;
    cursor_col = xPos;
}

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++) {
            writeData(bitmap[i + (n * bmpXSize)]);
        }
        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;

    for (n=0; n<row; n++) {
        locate(x,y);
        for(i=0; i<size_x; i++) {
            writeData( 0x00 );
        }
        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)
{
    ch -= fontStartChar;

    if (cursor_col > LCDCOLMAX - (fontWidth+1)) cursor_col = LCDCOLMAX - (fontWidth+1); // ensure space is available for the character
    if (cursor_row > LCDROWMAX - 1) cursor_row = LCDROWMAX - 1; // ensure space is available for the character
    lcd_buffer[cursor_row][cursor_col] = 0x00;
    for(int8_t j=0; j< fontHeight; j++) {
        lcd_buffer[cursor_row][cursor_col + j] =  fontStart[(ch)*fontWidth + j];
    }

    lcd_buffer[cursor_row][cursor_col + fontWidth] = 0x00;

    for(int8_t j=0; j< (fontWidth+1); j++) {
        if( mode == NORMAL )
            writeData(lcd_buffer[cursor_row][cursor_col++]);
        else
            writeData(lcd_buffer[cursor_row][cursor_col++] ^ 0xff);
        if (cursor_col >= LCDCOLMAX) {
            cursor_col=0;
            cursor_row++;
            if (cursor_row >= LCDROWMAX) cursor_row=0;
        }
    }
}

int  N3310LCD::_putc(int c) {
  writeChar(c, NORMAL);
  return c;
}
int N3310LCD::_getc() {
    return -1;
}

void N3310LCD::writeCharBig(BYTE xPos, BYTE yPos, BYTE ch, eDisplayMode mode)
{
    BYTE sendByte;
    int8_t colsUsed = 12;
    unsigned char* pFont = (unsigned char *) big_number;


    if(ch == '.') {
        ch = 10;
        colsUsed=5;
    } else if (ch == '+')
        ch = 11;
    else if (ch == '-')
        ch = 12;
    else if (ch == ':')
        ch = 13;
    else if (ch == '/')
        ch = 14;
    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);
                writeData((mode == NORMAL)? sendByte : (sendByte^0xff));
            }
        }
    */
    if (xPos > LCDCOLMAX - colsUsed) xPos = LCDCOLMAX - colsUsed ; // ensure space is available for the character
    if (yPos > LCDROWMAX - 3) yPos = LCDROWMAX - 3 ; // ensure space is available for the character

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

        for(int8_t j=0; j<colsUsed; j++) {
            sendByte =  *(pFont + ch*48 + i*16 + j);
            lcd_buffer[cursor_row][cursor_col + j] = (mode == NORMAL)? sendByte : (sendByte^0xff);
            writeData( lcd_buffer[cursor_row][cursor_col + j] );
        }
    }
}

/*
 * 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);
    writeData(value);
}


/*
 * 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);
    }
}