A library for LPM013M126A – JDI Color Memory LCD. This library is an inherited class from the “GraphicDisplay”, and Its functions are similar to “C12832_lcd” or ”SPI_TFT” library.

Dependents:   Test_ColorMemLCD rIoTwear_LCD

1.28" (176x176 193ppi) 8 Color Memory LCD of ultra-low power consumption in sub uA.

ColorMemLCD.cpp

Committer:
KURETA90
Date:
2016-06-23
Revision:
1:b035a997ec3f
Parent:
0:76a4e97c113f

File content as of revision 1:b035a997ec3f:

/*
 * mbed library for the JDI color memory LCD LPM013M126A
 * derived from C12832_lcd
 * Copyright (c) 2016  Tadayuki Okamoto 
 * Released under the MIT License: http://mbed.org/license/mit
 *
 * 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.
 */


#include "ColorMemLCD.h"
#include "mbed.h"

/** @def
 * LCD_Color SPI commands
 */
#define LCD_COLOR_CMD_UPDATE            (0x90) //!< Update Mode (4bit Data Mode)
#define LCD_COLOR_CMD_ALL_CLEAR         (0x20) //!< All Clear Mode
#define LCD_COLOR_CMD_NO_UPDATE         (0x00) //!< No Update Mode
#define LCD_COLOR_CMD_BLINKING_WHITE    (0x18) //!< Display Blinking Color Mode (White)
#define LCD_COLOR_CMD_BLINKING_BLACK    (0x10) //!< Display Blinking Color Mode (Black)
#define LCD_COLOR_CMD_INVERSION         (0x14) //!< Display Inversion Mode

/** Create a SPI_LCD object connected to SPI */
ColorMemLCD::ColorMemLCD( PinName mosi, PinName miso, PinName sclk, PinName cs, PinName disp, PinName power, const char *name )
    : GraphicsDisplay( name ), _spi( mosi, miso, sclk ), _cs( cs ), _disp( disp ), _power( power )
{
    /* initialize signal level */
    _power = 0;
    _disp  = 0;
    _cs    = 0;
    wait_us( 100 );

    /* initialize lcd module */
    _power = 1;
    _spi.format( 8,0 );         // 8bit mode3
    _spi.frequency( 2000000 );  // 2 Mhz SPI clock 
    _spi.write( 0x00 );         // dummy
    polarity = 0;
    blink_cmd = 0x00;

    /* initialize variables */
    char_x = 0;
    char_y = 0;
    trans_mode = LCD_TRANSMODE_OPAQUE;
    window_x = 0;
    window_y = 0;
    window_w = LCD_DISP_WIDTH;
    window_h = LCD_DISP_HEIGHT_MAX_BUF;

    /* set default color */
    foreground( LCD_COLOR_WHITE );
    background( LCD_COLOR_BLACK );

    /* initialize temporary buffer */
    memset( &cmd_buf[0], 0, sizeof(cmd_buf) );
    memset( &disp_buf[0], (char)( (_background & 0x0F ) | ( (_background & 0x0F ) << 4 ) ), sizeof(disp_buf) );
    memset( &file_buf[0], 0, sizeof(file_buf) );

    /* display turn ON */
    command_AllClear();
    _disp = 1;
}


/** Get the width of the screen in pixel */
int ColorMemLCD::width()
{
    return LCD_DISP_WIDTH;
}


/** Get the height of the screen in pixel */
int ColorMemLCD::height()
{
    return LCD_DISP_HEIGHT;
}


/** Set window region */
void ColorMemLCD::window( int x, int y, int w, int h )
{
#if ( LCD_DEVICE_HEIGHT != LCD_DISP_HEIGHT_MAX_BUF )
    if( ( ( x & 0x01 ) == 0x01 )||
        ( ( w & 0x01 ) == 0x01 ) ) {
        /* Parameter Error */
        GraphicsDisplay::window( x, y, w, h );
        return;
    }

    /* adjust region */
    if( x + w > LCD_DISP_WIDTH ) {
        w = LCD_DISP_WIDTH - x;
    }

    if( h > ( ( LCD_DISP_WIDTH / 2 ) * LCD_DISP_HEIGHT_MAX_BUF ) / ( w / 2 )  ) {
        h = ( ( LCD_DISP_WIDTH / 2 ) * LCD_DISP_HEIGHT_MAX_BUF ) / ( w / 2 );
    }

    if( ( window_x == x )&&
        ( window_y == y )&&
        ( window_w == w )&&
        ( window_h == h ) ) {
        /* Same Area */
        return;
    }

    window_x = x;
    window_y = y;
    window_w = w;
    window_h = h;

    /* Initialize Buffer */
    memset( &disp_buf[0], (char)( (_background & 0x0F ) | ( (_background & 0x0F ) << 4 ) ), sizeof(disp_buf) );

#endif /* ( LCD_DEVICE_HEIGHT != LCD_DISP_HEIGHT_MAX_BUF ) */

    GraphicsDisplay::window( x, y, w, h );
}


/** Set a pixel on the window memory */
void ColorMemLCD::pixel( int x, int y, int color )
{
    if( ( window_x > x )||
        ( ( window_x + window_w ) <= x )||
        ( window_y > y )||
        ( ( window_y + window_h ) <= y ) ) {
        /* out of display buffer */
        return;
    }

    if( ( x % 2 ) == 0 ) {
        disp_buf[ ( (window_w / 2) * ( y - window_y ) ) + ( ( x - window_x ) / 2 ) ] &= 0x0F;
        disp_buf[ ( (window_w / 2) * ( y - window_y ) ) + ( ( x - window_x ) / 2 ) ] |= ( ( color & 0x0F ) << 4 );
    }
    else {
        disp_buf[ ( (window_w / 2) * ( y - window_y ) ) + ( ( x - window_x ) / 2 ) ] &= 0xF0;
        disp_buf[ ( (window_w / 2) * ( y - window_y ) ) + ( ( x - window_x ) / 2 ) ] |= ( ( color & 0x0F )      );
    }
}


/** Set a pixel - for transrucent mode */
void ColorMemLCD::pixel_alpha( int x, int y, int color )
{
    if( ( window_x > x )||
        ( ( window_x + window_w ) <= x )||
        ( window_y > y )||
        ( ( window_y + window_h ) <= y ) ) {
        /* out of display buffer */
        return;
    }

    if( ( x % 2 ) == 0 ) {
        disp_buf[ ( (window_w / 2) * ( y - window_y ) ) + ( ( x - window_x ) / 2 ) ] &= ( ( ( color & 0x0F ) << 4 ) | 0x0F );
    }
    else {
        disp_buf[ ( (window_w / 2) * ( y - window_y ) ) + ( ( x - window_x ) / 2 ) ] &= ( ( ( color & 0x0F )      ) | 0xF0 );
    }
}


/** Fill the window memory with background color */
void ColorMemLCD::cls( void )
{
    memset( &disp_buf[0], (char)( (_background & 0x0F ) | ( (_background & 0x0F ) << 4 ) ), sizeof(disp_buf) );
}


/** draw a circle */
void ColorMemLCD::circle( int x0, int y0, int r, int color )
{
    int x = -r;
    int y = 0;
    int err = 2 - (2*r);
    int e2 = err;

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


/** draw a filled circle */
void ColorMemLCD::fillcircle( int x0, int y0, int r, int color )
{
    int x = -r;
    int y = 0;
    int err = 2 - (2*r);
    int e2 = err;

    do {
        vline( x0-x, y0-y, y0+y, color );
        vline( x0+x, y0-y, 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);
}


/** draw a horizontal line */
void ColorMemLCD::hline( int x0, int x1, int y, int color )
{
    int x;
    int direction;

    if( x0 == x1 ) {
        pixel( x0, y, color );
        return;
    }
    else if( x0 > x1 ) {
        direction = -1;
    }
    else {
        direction = 1;
    }

    for( x = x0 ; x <= x1 ; x += direction ) {
        pixel( x, y, color );
    }
}


/** draw a vertical line */
void ColorMemLCD::vline( int x, int y0, int y1, int color )
{
    int y;
    int direction;

    if( y0 == y1 ) {
        pixel( x, y0, color );
        return;
    }
    else if( y0 > y1 ) {
        direction = -1;
    }
    else {
        direction = 1;
    }

    for( y = y0 ; y <= y1 ; y += direction ) {
        pixel( x, y, color );
    }
}


/** draw a 1 pixel line */
void ColorMemLCD::line( int x0, int y0, int x1, int y1, int color )
{
    int dx = 0;
    int dy = 0;
    int dx_sym = 0;
    int dy_sym = 0;
    int dx_x2 = 0;
    int dy_x2 = 0;
    int di = 0;

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

    if( dx == 0 ) {        /* vertical line */
        vline( x0, y0, y1, color );
        return;
    }
    else if( dx > 0 ) {
        dx_sym = 1;
    }
    else {
        dx_sym = -1;
    }

    if( dy == 0 ) {        /* horizontal line */
        hline( x0, x1, y0, color );
        return;
    }
    else 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 );
    }
    return;
}


/** draw a rect */
void ColorMemLCD::rect( int x0, int y0, int x1, int y1, int color )
{
    hline( x0, x1, y0, color );

    vline( x0, y0, y1, color );

    hline( x0, x1, y1, color );

    vline( x1, y0, y1, color );
}


/** draw a filled rect */
void ColorMemLCD::fillrect(int x0, int y0, int x1, int y1, int color)
{
    int y;
    int direction;

    if( y0 == y1 ) {
        hline( x0, x1, y0, color );
        return;
    }
    else if( y0 > y1 ) {
        direction = -1;
    }
    else {
        direction = 1;
    }

    for( y = y0 ; y <= y1 ; y += direction ) {
        hline( x0, x1, y, color );
    }
}


/** setup cursor position */
void ColorMemLCD::locate( int x, int y )
{
    char_x = x;
    char_y = y;
}


/** calculate the max number of char in a line */
int ColorMemLCD::columns()
{
    return width() / font[1];
}


/** calculate the max number of columns */
int ColorMemLCD::rows()
{
    return height() / font[2];
}


/** put a char on the screen */
int ColorMemLCD::_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;
}


/** draw a character of selected font */
void ColorMemLCD::character( int x, int y, int c )
{
    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() - vert ) {
            char_y = 0;
        }
    }
    zeichen = &font[ ( ( c - 32 ) * offset ) + 4 ]; // start of char bitmap
    w = zeichen[0];                                 // width of actual char
    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 ) {
                if( trans_mode == LCD_TRANSMODE_OPAQUE ) {
                    pixel( x + i, y + j, _background );
                }
                else if( trans_mode == LCD_TRANSMODE_TRANSLUCENT ) {
                    pixel_alpha( x + i, y + j, _background );
                }
            } else {
                pixel( x + i, y + j, _foreground );
            }
        }
    }
    if( ( w + 2 ) < hor ) {                         // x offset to next char
        char_x += w + 2;
    }
    else {
        char_x += hor;
    }
}

/** draw a symbol of same format as "character"  */
void ColorMemLCD::symbol(unsigned int x, unsigned int y, unsigned char *symbol)
{
    unsigned int hor,vert,bpl,j,i,b; 
    unsigned char z;
    
    hor = symbol[0];                       // get hor size of font
    vert = symbol[1];                      // get vert size of font
    bpl = symbol[2];                       // bytes per line

    if( char_x + hor > width() ) {
        char_x = 0;
        char_y = char_y + vert;
        if( char_y >= height() - vert ) {
            char_y = 0;
        }
    }

    for( j = 0; j < vert ; j++ ) {                  //  vert line
        for( i = 0 ; i < hor ; i++ ) {              //  horz line
            z =  symbol[ bpl * i + ( ( j & 0xF8 ) >> 3 ) + 1 + 3 ];
            b = 1 << ( j & 0x07 );
            if( ( z & b ) == 0x00 ) {
                if( trans_mode == LCD_TRANSMODE_OPAQUE ) {
                    pixel( x + i, y + j, _background );
                }
                else if( trans_mode == LCD_TRANSMODE_TRANSLUCENT ) {
                    pixel_alpha( x + i, y + j, _background );
                }
            } else {
                pixel( x + i, y + j, _foreground );
            }
        }
    }
}


/** select the font  */
void ColorMemLCD::set_font( unsigned char* f )
{
    font = f;
}


/** set transpalent effect */
void ColorMemLCD::setTransMode( char mode )
{
    trans_mode = mode;
}


/** set a bitmap on the window buffer */
void ColorMemLCD::Bitmap4bit( int x, int y, int w, int h, unsigned char *bitmap )
{
    Bitmap4bit( x, y, w, h, bitmap, 0, 0, w, h );
}


/** set a bitmap on the window buffer  */
void ColorMemLCD::Bitmap4bit( int x, int y, int w, int h, unsigned char *bitmap, int bmp_x, int bmp_y, int bmp_w, int bmp_h )
{
    int i, j;

    if( ( x         < 0 )||
        ( y         < 0 )||
        ( w         <= 0 )||
        ( h         <= 0 )||
        ( bitmap == NULL )||
        ( bmp_x     < 0 )||
        ( bmp_y     < 0 )||
        ( bmp_w     <= 0 )||
        ( bmp_h     <= 0 )||
        ( ( x       & 0x01 ) == 0x01 )||
        ( ( w       & 0x01 ) == 0x01 )||
        ( ( bmp_x   & 0x01 ) == 0x01 )||
        ( ( bmp_w   & 0x01 ) == 0x01 ) ) {
        /* Parameter Error */
        return;
    }

    for( i = 0 ; i < h ; i++ ) {
        if( ( window_y > i + y )||
            ( ( window_y + window_h ) <= i + y )||
            ( ( bmp_h ) <= i + bmp_y ) ) {
            /* out of display buffer */
            continue;
        }
        for( j = 0 ; j < w ; j += 2 ) {
            if( ( window_x > j + x )||
                ( ( window_x + window_w ) <= j + x )||
                ( ( bmp_w ) <= j + bmp_x ) ) {
                /* out of display buffer */
                continue;
            }
            /* copy to display bufffer */
            disp_buf[ ( ( window_w / 2 ) * ( i + y - window_y ) ) + ( ( j + x - window_x ) / 2 ) ] = bitmap[ ( ( bmp_w / 2 ) * ( i + bmp_y ) ) + ( ( j + bmp_x ) / 2 ) ];
        }
    }
}


/** set a bitmap on the window buffer */
void ColorMemLCD::Bitmap1bit( int x, int y, int w, int h, unsigned char *bitmap )
{
    Bitmap1bit( x, y, w, h, bitmap, 0, 0, w, h );
}


/** set a bitmap on the window buffer  */
void ColorMemLCD::Bitmap1bit( int x, int y, int w, int h, unsigned char *bitmap, int bmp_x, int bmp_y, int bmp_w, int bmp_h )
{
    int i, j;
    int byte, offset;

    if( ( x         < 0 )||
        ( y         < 0 )||
        ( w         <= 0 )||
        ( h         <= 0 )||
        ( bitmap == NULL )||
        ( bmp_x     < 0 )||
        ( bmp_y     < 0 )||
        ( bmp_w     <= 0 )||
        ( bmp_h     <= 0 ) ) {
        /* Parameter Error */
        return;
    }

    for( i = 0 ; i < h ; i++ ) {
        if( ( window_y > i + y )||
            ( ( window_y + window_h ) <= i + y )||
            ( ( bmp_h ) <= i + bmp_y ) ) {
            /* out of display buffer */
            continue;
        }
        for( j = 0 ; j < w ; j ++ ) {
            if( ( window_x > j + x )||
                ( ( window_x + window_w ) <= j + x )||
                ( ( bmp_w ) <= j + bmp_x ) ) {
                /* out of display buffer */
                continue;
            }
            byte    = ( ( bmp_w * ( i + bmp_y ) ) + ( ( j + bmp_x ) ) ) / 8;
            offset  = ( ( bmp_w * ( i + bmp_y ) ) + ( ( j + bmp_x ) ) ) % 8;
            /* set to display bufffer */
            if( ( bitmap[ byte ] & ( 0x80 >> offset ) ) != 0x00 ) {
                /* Foregroud */
                pixel( ( j + x - window_x ), ( i + y - window_y ), _foreground );
            }
            else {
                /* Backgroud */
                if( trans_mode == LCD_TRANSMODE_OPAQUE ) {
                    pixel( ( j + x - window_x ), ( i + y - window_y ), _background );
                }
                else if( trans_mode == LCD_TRANSMODE_TRANSLUCENT ) {
                    pixel_alpha( ( j + x - window_x ), ( i + y - window_y ), _background );
                }
            }
        }
    }
}


/** Transfer to the LCD from diaply buffer */
void ColorMemLCD::update()
{
    int32_t         i;
    int    copy_width;

    if( window_x + window_w < LCD_DISP_WIDTH ) {
        copy_width = (window_w / 2);
    }
    else {
        copy_width = ( ( LCD_DISP_WIDTH - window_x ) / 2 );
    }

    for( i = 0 ; i < window_h ; i++ ) {

        if( window_y + i > LCD_DISP_HEIGHT ){
            /* out of window system */
            break;
        }

        /* initialize command buffer */
        memset( &cmd_buf[0], (char)( (_background & 0x0F ) | ( (_background & 0x0F ) << 4 ) ), sizeof(cmd_buf) );

        /* copy to command bufffer */
        memcpy( &cmd_buf[(window_x/2)], &disp_buf[ (window_w / 2) * i ], copy_width );

        /* send cmaoond request */
        sendLineCommand( &cmd_buf[0], window_y + i );
    }
}


/** Transfer a 24 bit BMP to the LCD from filesytem */
int ColorMemLCD::BMP_24( int x,  int y, const char *filenameBMP )
{
    FILE*       fp;
    int32_t     width;
    int32_t     height;
    int16_t     data_bit_size;
    bool        data_direction = false; 
//  uint32_t    filesize;
    uint32_t    data_offset;
    int32_t     i = 0;
    int32_t     j = 0;
    int32_t     line = 0;

    memset( &file_buf[0], 0, sizeof(file_buf) );

    fp = fopen( filenameBMP, "rb" );
    if( fp != NULL ) {
        /* read file header */
        fread( &file_buf[0], sizeof(char), 14, fp );

//      filesize    = file_buf[ 2] + ( file_buf[ 3] << 8 ) +  ( file_buf[ 4] << 16 ) +  ( file_buf[ 5] << 24 );
        data_offset = file_buf[10] + ( file_buf[11] << 8 ) +  ( file_buf[12] << 16 ) +  ( file_buf[13] << 24 );

        if( data_offset <= 14 ) {
            /* error */
            fclose(fp);
            return(0);
        }

        memset( &file_buf[0], 0, sizeof(file_buf) );

        /* read file header */
        fread( &file_buf[0], sizeof(char), (data_offset - 14), fp );

        if( data_offset == 0x0C ) {
            /* OS/2 format */
            width       = file_buf[ 4] + ( file_buf[ 5] << 8 );
            height      = file_buf[ 6] + ( file_buf[ 7] << 8 );
            data_bit_size   = file_buf[10] + ( file_buf[11] << 8 );
        }
        else if( data_offset == 0x36 ){
            /* Windows format */
            width       = file_buf[ 4] + ( file_buf[ 5] << 8 ) + ( file_buf[ 6] << 16 ) + ( file_buf[ 7] << 24 );
            height      = file_buf[ 8] + ( file_buf[ 9] << 8 ) + ( file_buf[10] << 16 ) + ( file_buf[11] << 24 );
            data_bit_size   = file_buf[14] + ( file_buf[15] << 8 );
        }
        else{
            /* Unknown format */
            fclose(fp);
            return(0);
        }

        if( data_bit_size != 24 ) {
            /* Not 24bit format */
            fclose(fp);
            return(0);
        }

        if( height < 0 ) {
            height *= -1;
            data_direction = true;
        }

        if( data_direction == true ) {
            line = i;
        }
        else {
            line = height - i - 1;
        }

        for( i = 0; i < height; i++ ) {

            if( data_direction == true ) {
                line = i + y;
            }
            else {
                line = height - i - 1 + y;
            }
            if( line >= LCD_DISP_HEIGHT ) {
                /* out of window system */
                continue;
            }

            /* initialize line display data with backgroud color */
            memset( &cmd_buf[0], (char)( (_background & 0x0F ) | ( (_background & 0x0F ) << 4 ) ), sizeof(cmd_buf) );

            if( ( line > window_y )&&
                ( line < window_y + window_h ) ) {
                /* inside display_buffer */
                memcpy( &cmd_buf[ ( window_x / 2 ) ], &disp_buf[ ( window_w / 2 ) * ( line - window_y ) ], ( window_w / 2 ) );
            }

            for( j = 0 ; j < width / 2 ; j++ ) {
                /* Read pixel */
                memset( &file_buf[0], 0, 6 );
                if( ( ( j * 2 ) + 1 ) < width ) {
                    fread( &file_buf[0], sizeof(char), 6, fp );
                }
                else if( ( ( j * 2 ) + 1 ) == width ){
                    fread( &file_buf[0], sizeof(char), 3, fp );
                }
                else {
                    break;
                }
                if( j + ( x / 2 ) >= (LCD_DISP_WIDTH/2) ) {
                    /* out of window system */
                    continue;
                }
                cmd_buf[ j + ( x / 2 ) ]  = ( ( file_buf[0] & 0x80 ) >> 2 );   /* B */
                cmd_buf[ j + ( x / 2 ) ] |= ( ( file_buf[1] & 0x80 ) >> 1 );   /* G */
                cmd_buf[ j + ( x / 2 ) ] |=   ( file_buf[2] & 0x80 );          /* R */

                if( ( ( j * 2 ) + 1 ) < width ) {
                    cmd_buf[ j + ( x / 2 ) ] |= ( ( file_buf[3] & 0x80 ) >> 6 );   /* B */
                    cmd_buf[ j + ( x / 2 ) ] |= ( ( file_buf[4] & 0x80 ) >> 5 );   /* G */
                    cmd_buf[ j + ( x / 2 ) ] |= ( ( file_buf[5] & 0x80 ) >> 4 );   /* R */
                }
            }

            /* send cmaoond request */
            sendLineCommand( &cmd_buf[0], line );

            /* copy to display buffer */
            if( ( line > window_y )&&
                ( line < window_y + window_h ) ) {
                /* inside display_buffer */
                memcpy( &disp_buf[ ( window_w / 2 ) * ( line - window_y ) ], &cmd_buf[ ( window_x / 2 ) ], ( window_w / 2 ) );
            }
        }
        fclose(fp);
    }

    return(1);
}


/** send data packet */
void ColorMemLCD::sendLineCommand( char* line_cmd, int line  )
{
    int32_t j;

    if( ( line < 0 )||
        ( line >= LCD_DEVICE_HEIGHT ) ) {
        /* out of device size */
        return;
    }

    wait_us(6);
    _cs = 1;
    wait_us(6);
    _spi.write( LCD_COLOR_CMD_UPDATE | ( polarity << 6 ) ); // Command
    _spi.write( line + 1 );             // line

    for( j = 0 ; j < (LCD_DISP_WIDTH/2) ; j++ ) {
        if( j >= (LCD_DEVICE_WIDTH/2) ) {
            /* out of device size */
            break;
        }
        _spi.write(line_cmd[j]);        // data
    }
    for( ; j < (LCD_DEVICE_WIDTH/2) ; j++ ) {
        /* padding to device size */
        _spi.write( 0x00 );
    }

    _spi.write( 0x00 );
    _spi.write( 0x00 );
    wait_us(6);
    _cs = 0;
}


/** Toggle the polarity at evry scecond */
void ColorMemLCD::polling()
{
    if( polarity == 0 ) {
        polarity = 1;
    }
    else {
        polarity = 0;
    }

    if( _cs == 1 ) {
        return;
    }

    command_SetState();
}


/** Command for setting the state of LCD */
void ColorMemLCD::command_SetState()
{
    wait_us( 6 );
    _cs = 1;
    wait_us( 6 );
    _spi.write( blink_cmd | ( polarity << 6 ));
    _spi.write( 0x00 );
    wait_us(6);
    _cs = 0;
}


/** Command to clear whole the LCD */
void ColorMemLCD::command_AllClear()
{
    wait_us( 6 );
    _cs = 1;
    wait_us( 6 );
    _spi.write( LCD_COLOR_CMD_ALL_CLEAR | ( polarity << 6 ));
    _spi.write( 0x00 );
    wait_us(6);
    _cs = 0;
}


/** Command to blink */
void ColorMemLCD::setBlinkMode( char mode )
{
    switch( mode ) {
        case LCD_BLINKMODE_NONE:
            /* Blinking None    */
            blink_cmd = LCD_COLOR_CMD_NO_UPDATE;
            break;
        case LCD_BLINKMODE_WHITE:
            /* Blinking White   */
            blink_cmd = LCD_COLOR_CMD_BLINKING_WHITE;
            break;
        case LCD_BLINKMODE_BLACK:
            /* Blinking Black   */
            blink_cmd = LCD_COLOR_CMD_BLINKING_BLACK;
            break;
        case LCD_BLINKMODE_INVERSE:
            /* Inversion Mode   */
            blink_cmd = LCD_COLOR_CMD_INVERSION;
            break;
        default:
            /* No Update */
            blink_cmd = LCD_COLOR_CMD_NO_UPDATE;
            break;
    }

    _cs = 1;
    wait_us( 6 );
    _spi.write( blink_cmd | ( polarity << 6 ));
    _spi.write( 0x00 );
    wait_us(6);
    _cs = 0;
}