PCD8544 multiscreen

Revision:
0:61dcd2c0299a
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/PCD8544MS.cpp	Fri Jun 15 18:37:00 2012 +0000
@@ -0,0 +1,925 @@
+/* mbed PCD8544 - Graphic Library for driving monochrome displays based on
+ *  the PCD8544  48 x 84 pixels matrix LCD controller/driver
+ *  used in Nokia 3310, 3315, 3330, 3350, 3410, 3210,  5110, 5120, 5130, 5160, 6110, 6150
+ *
+ * Copyright (c) 2011, Wim De Roeve
+ * partial port of the code found on http://serdisplib.sourceforge.net/ser/pcd8544.html#links
+ * and by Petras Saduikis <petras@petras.co.uk>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the updaSoftware, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 "PCD8544MS.h"
+
+#include "fonts/font_3x5.h"
+#include "fonts/font_5x7.h"
+#include "fonts/font_6x8.h"
+#include "fonts/font_8x8.h"
+#include "fonts/font_8x12.h"
+#include "fonts/font_16x20.h"
+#include "fonts/font_16x24.h"
+
+#include "DebugTrace.h"
+#include "sstream"
+#include "stdio.h"
+#include "stringman.h"
+
+#define GLCD_CS6_ON            0x01   //P0
+#define GLCD_RESET_ON          0x02   //P1
+#define GLCD_CS1_ON            0x04   //P2
+#define GLCD_CS5_ON            0x08   //P3
+#define GLCD_DC_ON             0x10   //P4
+#define GLCD_CS2_ON            0x20   //P5
+#define GLCD_CS3_ON            0x40   //P6
+#define GLCD_CS4_ON            0x80   //P7
+
+#define TLCD_RS_ON             0x1000 //P12
+#define TLCD_E1_ON             0x2000 //P13
+#define TLCD_E2_ON             0x4000 //P14
+#define TLCD_BACKLIGHT_ON      0x8000 //P15
+
+/* Display ON/OFF Control defines */
+#define DON                0x0F  //0b00001111  Display on 
+#define DOFF               0x0B  //0b00001011  Display off 
+#define CURSOR_ON          0x0F  //0b00001111  Cursor on 
+#define CURSOR_OFF         OxOD  //0b00001101  Cursor off 
+#define BLINK_ON           0x0F  //0b00001111  Cursor Blink 
+#define BLINK_OFF          0x0E  //0b00001110  Cursor No Blink 
+
+/* Cursor or Display Shift defines */
+#define SHIFT_CUR_LEFT     Ox13  //0b00010011  Cursor shifts to the left 
+#define SHIFT_CUR_RIGHT    Ox17  //0b00010111  Cursor shifts to the right 
+#define SHIFT_DISP_LEFT    Ox1B  //0b00011011  Display shifts to the left 
+#define SHIFT_DISP_RIGHT   0x1F  //0b00011111  Display shifts to the right 
+
+/* Function Set defines */
+#define EIGHT_BITMODE      0x03  //0b00000011  8-bit Interface D4-D7
+#define FOUR_BITMODE       0x02  //0b00000010  4-bit Interface D4-D7
+#define LINE_5X7           0x30  //0b00110000
+#define LINE_5X10          0x34  //0b00110100
+#define LINES_5X7          0x38  //0b00111000
+
+// Addtional define to support display mode
+
+#define DISP_FLIP_NONE     0x00  //0b00111100  No flip
+#define CLEAR_LCD          0x01  //0b00000001 
+
+/* Number of pixels on the LCD */
+
+#define HIGH  1
+#define LOW   0
+#define TRUE  1
+#define FALSE 0
+
+/* Display control command */
+#define EXTENDEDSET   0x21
+#define STANDARDSET   0x20
+#define DISPLAYOFF    0x08  // switch off display 
+#define ALL_SEG_ON    0x09  // switch on display and set to all pixels on
+#define NORMAL_MODE   0x0C  // NOREVERSE
+#define INVERSE_MODE  0x0D  // REVERSE
+
+#define SET_ADDRES_X  0x80
+#define SET_ADDRES_Y  0x40
+
+
+DebugTrace pc_PCD8544(ON, TO_SERIAL);
+
+/*
+       PCD8544 from Philips Semiconductors is
+       48 x 84 pixels monochrome matrix LCD controller/driver
+
+       generic for LPH7366, LPH7677, and LPH7779; no backlight
+
+       model name (of display)     type     used in cellphones
+       LPH 7366         2     Nokia 5110, 5120, 5130, 5160, 6110, 6150
+       LPH 7677         1     Nokia 3210
+       LPH 7779         1     Nokia 3310, 3315, 3330, 3350, 3410
+
+
+       +-------------------------+
+       |     1 2 3 4 5 6 7 8     |
+       |     # # # # # # # #     |
+       |  ===#=#=#=#=#=#=#=#===  |  Red     1 .. VDD  - chip power supply +3.3V
+       +--=====================--+  Green   2 .. SCLK - serial clock line of LCD
+       |                         |  Yellow  3 .. SI   - serial data input of LCD
+       |                         |  Gray    4 .. D/C  - command/data switch
+       |        rear view        |  Blue    5 .. /CS  - active low chip select
+       |  connector is visible   |  Black   6 .. GND  - for VDD
+       |                         |          7 .. Vout - output of display-internal dc/dc converter
+       |         LPH7779         |  White   8 .. /RES - active low reset
+       |                         |
+       +-------------------------+
+
+*/
+
+
+PCD8544MS::PCD8544MS(PinName mosi, PinName miso, PinName sclk, PinName sda, PinName scl,int i2cAddress, bool TextLCD, bool backlight):
+        _spi(mosi, miso, sclk),_i2c(sda, scl) {
+
+    _i2cAddress = i2cAddress;
+//   _type = type;
+
+    if (TextLCD) {
+        TLCD_reset();
+        _columns = 16;
+        _rows = 2;
+        _backlight=backlight;
+    }
+
+    GLCD_reset();
+}
+
+void PCD8544MS::writeI2CByte(int data) {
+    char cmd[2];
+    cmd[0] = (data & 0xFF);
+    cmd[1] = (data >> 8);
+    _i2c.write(_i2cAddress, cmd, 2);
+    // pc_PCD8544.traceOut("I2C=%i ",data);
+
+}
+
+// ############# TEXTLCD FUNCTIONS ###################
+
+void PCD8544MS::TLCD_reset() {
+    for (int i=0; i<3; i++) {
+        TLCD_writeNibble(EIGHT_BITMODE,false);
+        wait(0.00164);      // this command takes 1.64ms, so wait for it
+    }
+    TLCD_writeNibble(FOUR_BITMODE,false); // 4-bit mode
+
+    TLCD_writeCommand(0x28);    // Function set 001 BW N F - -
+    TLCD_writeCommand(0x0C);
+    TLCD_writeCommand(0x6);  //  Cursor Direction and Display Shift : 0000 01 CD S (CD 0-left, 1-right S(hift) 0-no, 1-yes
+}
+
+void PCD8544MS::TLCD_writeNibble(int data, bool rs) {
+
+    data = ((data & 0xF) << 8) || GLCD_RESET_ON || GLCD_CS1_ON ||  GLCD_CS2_ON || GLCD_CS3_ON || GLCD_CS4_ON || GLCD_CS5_ON || GLCD_CS6_ON ;
+
+    if (_backlight)
+        data= data  | TLCD_BACKLIGHT_ON;
+
+    if (rs) {
+        data = data | TLCD_RS_ON; // set rs bit
+    }
+
+    writeI2CByte(data | TLCD_E1_ON); // E=1
+
+    wait(0.000040f);
+    writeI2CByte(data);   // E=0
+
+    wait(0.000040f);
+    writeI2CByte(data | TLCD_E1_ON);  // E=1
+}
+
+
+void PCD8544MS::TLCD_writeByte(int data, bool rs) {
+    TLCD_writeNibble(data >> 4 , rs);
+    TLCD_writeNibble(data >> 0 , rs);
+}
+
+void PCD8544MS::TLCD_writeCommand(int command) {
+    // RS = 0;
+    TLCD_writeByte(command,false);
+}
+
+void PCD8544MS::TLCD_writeData(int data) {
+    //RS = 1
+    TLCD_writeByte(data,true);
+
+    _column++;
+    if (_column >= _columns) {
+        TLCD_newline();
+    }
+}
+
+int PCD8544MS::_putc(int value) {
+    if (value == '\n') {
+        TLCD_newline();
+    } else {
+        TLCD_writeData(value);
+    }
+    return value;
+}
+
+int PCD8544MS::_getc() {
+    return 0;
+}
+
+void PCD8544MS::TLCD_backlight(bool status) {
+    _backlight=status;
+    if (_backlight)
+        writeI2CByte(TLCD_BACKLIGHT_ON | TLCD_E1_ON | TLCD_E2_ON | GLCD_CS1_ON);
+    else
+        writeI2CByte(TLCD_E1_ON | TLCD_E2_ON | GLCD_CS1_ON);
+}
+
+
+void PCD8544MS::TLCD_newline() {
+    _column = 0;
+    _row++;
+    if (_row >= _rows) {
+        _row = 0;
+    }
+    TLCD_locate(_column, _row);
+}
+
+
+void PCD8544MS::TLCD_locate(int column, int row) {
+    if (column < 0 || column >= _columns || row < 0 || row >= _rows) {
+        error("locate(%d,%d) out of range on %dx%d display", column, row, _columns, _rows);
+        return;
+    }
+
+    _row = row;
+    _column = column;
+    int address = 0x80 + (_row * 40) + _column; // memory starts at 0x80, and is 40 chars long per row
+    // pc_LCD.traceOut("locate %dx%d\r\n", column, row);
+    TLCD_writeCommand(address);
+}
+
+
+void PCD8544MS::TLCD_cls() {
+    TLCD_writeCommand(0x01); // Clear Display
+    wait(0.00164f);     // This command takes 1.64 ms
+    TLCD_locate(0, 0);
+}
+
+
+
+// ############# GRAPHICLCD FUNCTIONS ###################
+
+void PCD8544MS::GLCD_reset() {
+
+    /* reset lcd
+
+      After reset, the LCD driver has the following state:
+      - Power-down mode (bit PD = 1)
+      - Horizontal addressing (bit V = 0)
+      - normal instruction set (bit H = 0)
+      - Display blank (bit E = D = 0)
+      - Address counter X6 to X0 = 0; Y2 to Y0 = 0
+      - Temperature control mode (TC1 TC0 = 0)
+      - Bias system (BS2 to BS0 = 0)
+      - VLCD is equal to 0, the HV generator is switched off
+       (VOP6 to VOP0 = 0)
+      - After power-on, the RAM contents are undefined.
+    */
+
+
+    GLCD_writeI2C(HIGH,LOW,HIGH,0); // all screens
+
+    _spi.format(8,0);
+    _spi.frequency(1000000);
+
+    pc_PCD8544.traceOut("\r\nreset GLCD ");
+
+    //_cs=HIGH;
+    //_reset=HIGH;
+
+
+    // for (int i=1;i<=maxscreen;i++) {
+
+    wait_ms(1);
+    //_reset=LOW;
+    GLCD_writeI2C(LOW,LOW,HIGH,0);
+
+    wait_ms(1);
+    //_reset = HIGH;
+    GLCD_writeI2C(HIGH,LOW,HIGH,0);
+
+    GLCD_writeCmd(EXTENDEDSET,1,0);   // folowing commands are extended ones
+    GLCD_writeCmd(0xc8,0,0);          // Set Voltage 0x80+value: set contrast
+    GLCD_writeCmd(0x06,0,0);          // set temp coefficient
+    GLCD_writeCmd(0x13,0,0);          // set BIAS mode 1:48
+    GLCD_writeCmd(STANDARDSET,0,0);   // STANDARDSET: following commands are standard ones
+
+    GLCD_writeCmd(NORMAL_MODE,2,0);
+    _LoMark = 0;
+    _HiMark = LCD_CACHE_SIZE - 1;
+
+    GLCD_cls(0,TRUE);
+}
+
+void PCD8544MS::GLCD_writeCmd(BYTE data, BYTE CF, int screen) {
+    //_cs = LOW;
+    //_dc = LOW;
+    // _spi.write(data);
+
+//    pc_PCD8544.traceOut("\r\n %i %i %i ",(CF & 1),data,(CF & 2));
+
+    if ((CF & 1)==1) {
+        GLCD_writeI2C(HIGH,LOW,LOW,screen);
+        wait_ms(1);
+    }
+
+    _spi.write(data);
+
+    if ((CF & 2)==2) {
+        GLCD_writeI2C(HIGH,LOW,HIGH,screen);
+    }
+
+    //_cs = HIGH;
+
+}
+
+void PCD8544MS::GLCD_writeData(BYTE data, BYTE CF, int screen) {
+    // _cs = LOW;
+    //_dc = HIGH;
+    //_spi.write(data);
+
+    if ((CF & 1)==1) {
+        GLCD_writeI2C(HIGH,HIGH,LOW,screen);
+        wait_ms(1);
+    }
+
+    _spi.write(data);
+
+    if ((CF & 2)==2) {
+        GLCD_writeI2C(HIGH,HIGH,HIGH,screen);
+    }
+
+    //  _cs = HIGH;
+
+}
+
+void PCD8544MS::GLCD_writeI2C(bool reset, bool dc, bool cs,int screen) {
+
+    int cb=TLCD_E1_ON | TLCD_E2_ON;  // prevent TextLCD for
+
+    if (reset==HIGH) cb = cb | GLCD_RESET_ON;
+    if (dc==HIGH) cb = cb | GLCD_DC_ON;
+
+    if (cs==HIGH) {
+        cb = cb | GLCD_CS1_ON |  GLCD_CS2_ON | GLCD_CS3_ON | GLCD_CS4_ON | GLCD_CS5_ON | GLCD_CS6_ON ;
+    } else {
+        switch (screen)  {
+            case 1: {
+                cb = cb | GLCD_CS2_ON | GLCD_CS3_ON | GLCD_CS4_ON | GLCD_CS5_ON | GLCD_CS6_ON;
+                break;
+            }
+            case 2: {
+                cb = cb | GLCD_CS1_ON | GLCD_CS3_ON | GLCD_CS4_ON | GLCD_CS5_ON | GLCD_CS6_ON;
+                break;
+            }
+            case 3: {
+                cb = cb | GLCD_CS1_ON |  GLCD_CS2_ON | GLCD_CS4_ON | GLCD_CS5_ON | GLCD_CS6_ON;
+                break;
+            }
+            case 4: {
+                cb = cb | GLCD_CS1_ON |  GLCD_CS2_ON | GLCD_CS3_ON | GLCD_CS5_ON | GLCD_CS6_ON;
+                break;
+            }
+            case 5: {
+                cb = cb | GLCD_CS1_ON |  GLCD_CS2_ON | GLCD_CS3_ON | GLCD_CS4_ON | GLCD_CS6_ON;
+                break;
+            }
+            case 6: {
+                cb = cb | GLCD_CS1_ON |  GLCD_CS2_ON | GLCD_CS3_ON | GLCD_CS4_ON | GLCD_CS5_ON;
+                break;
+            }
+            default: {
+                break;
+            }
+        }
+    }
+
+
+    writeI2CByte(cb);
+
+}
+
+void PCD8544MS::GLCD_close() {
+    GLCD_writeCmd(DISPLAYOFF,3,0);
+    GLCD_writeI2C(HIGH,HIGH,HIGH,0);
+//   _cs    = HIGH;
+//   _reset = HIGH;
+
+}
+
+//  GRAPHICAL functions
+
+void PCD8544MS::GLCD_cls(int screen,bool fupdate) {
+//    pc_PCD8544.traceOut("\r\ncls %i ",LCD_CACHE_SIZE);
+
+    for (int i = 0; i < LCD_CACHE_SIZE ; i++) {
+        //    pc_PCD8544.traceOut("%i",i);
+        LcdCache[i]=0x00;
+    }
+    _LoMark = 0;
+    _HiMark = LCD_CACHE_SIZE - 1;
+
+//     pc_PCD8544.traceOut("\r\nfupdate");
+    if (fupdate)
+        GLCD_update(screen);
+}
+
+void PCD8544MS::GLCD_update(int screen) {
+//   pc_PCD8544.traceOut("\r\nupdate");
+    if ( _LoMark < 0 )
+        _LoMark = 0;
+    else if ( _LoMark >= LCD_CACHE_SIZE )
+        _LoMark = LCD_CACHE_SIZE - 1;
+    if ( _HiMark < 0 )
+        _HiMark = 0;
+    else if ( _HiMark >= LCD_CACHE_SIZE )
+        _HiMark = LCD_CACHE_SIZE - 1;
+
+    GLCD_writeCmd(SET_ADDRES_X | (_LoMark % LCD_X_RES),1,screen);
+    GLCD_writeCmd(SET_ADDRES_Y | (_LoMark / LCD_X_RES),2,screen);
+
+    GLCD_writeI2C(HIGH,HIGH,LOW,screen);
+    wait_ms(1);
+
+    for (int i = _LoMark; i <= _HiMark; i++ ) {
+        _spi.write(LcdCache[i]);
+        //writeData( );
+    }
+    GLCD_writeI2C(HIGH,HIGH,HIGH,screen);
+    _LoMark = LCD_CACHE_SIZE - 1;
+    _HiMark = 0;
+}
+
+
+
+void PCD8544MS::GLCD_locate(BYTE x0, BYTE y0) {
+    LcdCacheIdx = x0*LCD_BANKS + y0 * LCD_X_RES;
+}
+
+// Bitmap
+
+void PCD8544MS::GLCD_drawBitmap(BYTE x0, BYTE y0, const unsigned char* bitmap, BYTE bmpXSize, BYTE bmpYSize,BYTE fupdate,int screen) {
+    BYTE row;
+    //  pc_PCD8544.traceOut("\r\ndrawbitmap");
+
+    if (0 == bmpYSize % 8)
+        row = bmpYSize/8;
+    else
+        row = bmpYSize/8 + 1;
+
+    _LoMark= 0;
+    _HiMark= LCD_CACHE_SIZE - 1;
+
+    for (BYTE n = 0; n < row; n++) {
+        GLCD_locate(x0, y0);
+
+        for (BYTE i = 0; i < bmpXSize; i++) {
+            LcdCache[LcdCacheIdx+ i]=bitmap[i + (n * bmpXSize)];
+        }
+        y0++;
+    }
+    if (fupdate==TRUE)
+        GLCD_update(screen);
+}
+
+void PCD8544MS::GLCD_writeString(BYTE x0, BYTE y0, char* string,  eFonts font,ePixelMode pmode,eDisplayMode dmode,eSpaceMode smode, BYTE fupdate,int screen) {
+
+//   pc_PCD8544.traceOut("\r\nwriteString");
+    GLCD_locate(x0, y0);
+    chooseFont(font);
+
+    while (*string) {
+        GLCD_writeChar(x0,y0,*string++,font,pmode, dmode, FALSE,screen);
+        x0+=_font_width;   // width +1;
+        if (smode==SPACE_NORMAL)
+            x0++;
+    }
+    if (fupdate==TRUE)
+        GLCD_update(screen);
+}
+
+void PCD8544MS::chooseFont(eFonts font) {
+
+    switch (font) {
+
+        case VERYSMALLFONT: {
+            _font_width  = FONT3x5_WIDTH;
+            _font_height = FONT3x5_HEIGHT;
+            _font_start  = FONT3x5_START;
+            _font_end    = FONT3x5_END;
+            _font_bytes  = FONT3x5_BYTES;
+
+            _pFont = (unsigned char*) font_3x5;
+
+            break;
+        }
+        case TINYFONT: {
+            _font_width  = FONT5x7_WIDTH;
+            _font_height = FONT5x7_HEIGHT;
+            _font_start  = FONT5x7_START;
+            _font_end    = FONT5x7_END;
+            _font_bytes  = FONT5x7_BYTES;
+
+            _pFont = (unsigned char*) font_5x7;
+
+            break;
+        }
+
+        case SMALLFONT: {
+            _font_width  = FONT6x8_WIDTH;
+            _font_height = FONT6x8_HEIGHT;
+            _font_start  = FONT6x8_START;
+            _font_end    = FONT6x8_END;
+            _font_bytes  = FONT6x8_BYTES;
+
+            _pFont = (unsigned char*) font_6x8;
+
+            break;
+        }
+        case NORMALFONT: {
+            _font_width  = FONT8x8_WIDTH;
+            _font_height = FONT8x8_HEIGHT;
+            _font_start  = FONT8x8_START;
+            _font_end    = FONT8x8_END;
+            _font_bytes  = FONT8x8_BYTES;
+
+            _pFont = (unsigned char*) font_8x8;
+
+            break;
+        }
+        case BIGFONT: {
+            _font_width  = FONT8x12_WIDTH;
+            _font_height = FONT8x12_HEIGHT;
+            _font_start  = FONT8x12_START;
+            _font_end    = FONT8x12_END;
+            _font_bytes  = FONT8x12_BYTES;
+
+            _pFont = (unsigned char*) font_8x12;
+
+            break;
+        }
+
+        case TIMENUMBERFONT: {
+            _font_width  = FONT16x20_WIDTH;
+            _font_height = FONT16x20_HEIGHT;
+            _font_start  = FONT16x20_START;
+            _font_end    = FONT16x20_END;
+            _font_bytes  = FONT16x20_BYTES;
+
+            _pFont = (unsigned char*) font_16x20;
+
+            break;
+        }
+
+        case BIGNUMBERFONT: {
+            _font_width  = FONT16x24_WIDTH;
+            _font_height = FONT16x24_HEIGHT;
+            _font_start  = FONT16x24_START;
+            _font_end    = FONT16x24_END;
+            _font_bytes  = FONT16x24_BYTES;
+
+            _pFont = (unsigned char*) font_16x24;
+
+            break;
+        }
+    }
+}
+
+void PCD8544MS::GLCD_writeChar(BYTE x0, BYTE y0, BYTE ch,  eFonts font, ePixelMode pmode,eDisplayMode mode,BYTE fupdate,int screen) {
+    BYTE sendByte;
+
+    chooseFont(font);
+
+    if ((ch <= _font_start) || (ch > _font_end))
+        ch=_font_start;
+
+    ch -= _font_start;
+
+
+    /* for (BYTE i = 0; i < 3; i++) {
+         locate(x, y + i);
+
+         for (BYTE j = 0; j < 16; j++) {
+             sendByte =  *(pFont + ch*48 + i*16 + j);
+             writeData((mode == NORMAL)? sendByte : (sendByte^0xff));
+         }
+     }*/
+
+
+    for (int i = 0; i < _font_width; i++ ) {
+        for (int f=0; f<_font_bytes; f++) {
+            sendByte = *(_pFont + ch*_font_width*_font_bytes +f*_font_width+i);
+            sendByte = ((mode == DISPLAY_NORMAL)? sendByte:(sendByte ^ 0xff));
+
+            for (int j=0 ; j<_font_height; j++) {
+                if ((sendByte & 0x01) == 0x01) {
+                    GLCD_drawpixel(x0,y0+j+f*8,PIXEL_ON,FALSE,screen);
+                } else {
+                    GLCD_drawpixel(x0,y0+j+f*8,PIXEL_OFF,FALSE,screen);
+                }
+                sendByte=sendByte>>1;
+            }
+        }
+        x0++;
+    }
+
+
+    if (fupdate==TRUE)
+        GLCD_update(screen);
+}
+
+
+void PCD8544MS::GLCD_drawpixel(BYTE x0, BYTE  y0, ePixelMode mode,BYTE fupdate,int screen) {
+    uint16_t index;
+    BYTE offset;
+    BYTE data;
+
+    if ( x0 > LCD_X_RES-1 ) return;
+    if ( y0 > LCD_Y_RES-1 ) return;
+
+    index = ((y0 / 8) * LCD_X_RES) + x0;
+    offset = y0 - ((y0 / 8) * 8);
+
+    data = LcdCache[index];
+
+    if ( mode == PIXEL_OFF ) {
+        data &= (~(0x01 << offset));
+    } else if ( mode == PIXEL_ON ) {
+        data |= (0x01 << offset);
+    } else if ( mode == PIXEL_XOR ) {
+        data ^= (0x01 << offset);
+    }
+    LcdCache[index] = data;
+
+    if ( index < _LoMark ) {
+        _LoMark = index;
+    }
+    if ( index > _HiMark ) {
+        _HiMark = index;
+    }
+    if (fupdate==TRUE)
+        GLCD_update(screen);
+}
+
+void PCD8544MS::GLCD_drawline(BYTE  x0, BYTE y0, BYTE x1, BYTE y1, ePixelMode mode,BYTE fupdate,int screen) {
+    int dx, dy, stepx, stepy, fraction;
+
+    dy = y1 - y0;
+    dx = x1 - x0;
+    if ( dy < 0 ) {
+        dy = -dy;
+        stepy = -1;
+    } else {
+        stepy = 1;
+    }
+    if ( dx < 0 ) {
+        dx = -dx;
+        stepx = -1;
+    } else {
+        stepx = 1;
+    }
+    dx <<= 1;
+    dy <<= 1;
+
+    GLCD_drawpixel( x0, y0, mode , FALSE,screen);
+    if ( dx > dy ) {
+        fraction = dy - (dx >> 1);
+        while ( x0 != x1 ) {
+            if ( fraction >= 0 ) {
+                y0 += stepy;
+                fraction -= dx;
+            }
+            x0 += stepx;
+            fraction += dy;
+            GLCD_drawpixel( x0, y0, mode , FALSE,screen);
+        }
+    } else {
+        fraction = dx - (dy >> 1);
+        while ( y0 != y1 ) {
+            if ( fraction >= 0 ) {
+                x0 += stepx;
+                fraction -= dy;
+            }
+            y0 += stepy;
+            fraction += dx;
+            GLCD_drawpixel( x0, y0, mode , FALSE,screen);
+        }
+    }
+    if (fupdate==TRUE)
+        GLCD_update(screen);
+}
+
+void PCD8544MS::GLCD_drawrectangle(BYTE  x0, BYTE y0, BYTE x1, BYTE y1, eFillMode fill, ePixelMode mode,BYTE fupdate,int screen) {
+    if (fill==1) {
+        BYTE i, xmin, xmax, ymin, ymax;
+        if (x0 < x1) { // Find x min and max
+            xmin = x0;
+            xmax = x1;
+        } else {
+            xmin = x1;
+            xmax = x0;
+        }
+        if (y0 < y1) { // Find the y min and max
+            ymin = y0;
+            ymax = y1;
+        } else {
+            ymin = y1;
+            ymax = y0;
+        }
+        for (; xmin <= xmax; ++xmin) {
+            for (i=ymin; i<=ymax; ++i) {
+                GLCD_drawpixel(xmin, i, mode, FALSE,screen);
+            }
+        }
+    } else {
+        GLCD_drawline(x0, y0, x1, y0, mode, FALSE,screen); // Draw the 4 sides
+        GLCD_drawline(x0, y1, x1, y1, mode, FALSE,screen);
+        GLCD_drawline(x0, y0, x0, y1, mode, FALSE,screen);
+        GLCD_drawline(x1, y0, x1, y1, mode, FALSE,screen);
+    }
+    if (fupdate==TRUE)
+        GLCD_update(screen);
+}
+
+
+void  PCD8544MS::GLCD_drawcircle(BYTE x0, BYTE y0, BYTE radius, eFillMode fill, ePixelMode mode, BYTE fupdate,int screen) {
+    int err, x, y;
+
+    err = -radius;
+    x   = radius;
+    y   = 0;
+
+    while (x >= y) {
+        if (fill==1) {
+            GLCD_drawline(x0 - x, y0 + y, x0 + x, y0 + y, mode,FALSE,screen);
+            GLCD_drawline(x0 - x, y0 - y, x0 + x, y0 - y, mode,FALSE,screen);
+            GLCD_drawline(x0 - y, y0 + x, x0 + y, y0 + x, mode,FALSE,screen);
+            GLCD_drawline(x0 - y, y0 - x, x0 + y, y0 - x, mode,FALSE,screen);
+        } else {
+            GLCD_drawpixel(x0 + x, y0 + y, mode,FALSE,screen);
+            GLCD_drawpixel(x0 - x, y0 + y, mode,FALSE,screen);
+            GLCD_drawpixel(x0 + x, y0 - y, mode,FALSE,screen);
+            GLCD_drawpixel(x0 - x, y0 - y, mode,FALSE,screen);
+            GLCD_drawpixel(x0 + y, y0 + x, mode,FALSE,screen);
+            GLCD_drawpixel(x0 - y, y0 + x, mode,FALSE,screen);
+            GLCD_drawpixel(x0 + y, y0 - x, mode,FALSE,screen);
+            GLCD_drawpixel(x0 - y, y0 - x, mode,FALSE,screen);
+        }
+        err += y;
+        y++;
+        err += y;
+        if (err >= 0) {
+            x--;
+            err -= x;
+            err -= x;
+        }
+    }
+
+    if (fupdate==TRUE)
+        GLCD_update(screen);
+
+}
+
+void PCD8544MS::GLCD_drawprogressbar(BYTE  x0, BYTE y0, BYTE w, BYTE h, BYTE percentage,BYTE fupdate,int screen) {
+    GLCD_drawrectangle(x0,y0,x0+w,y0+h,FILL_OFF,PIXEL_ON, FALSE,screen);
+    GLCD_drawrectangle(x0+2,y0+2,x0+w-2,y0+h-2,FILL_ON,PIXEL_OFF, FALSE,screen);
+    GLCD_drawrectangle(x0+2,y0+2,x0+2+(percentage*(w-4)/100),y0+h-2,FILL_ON,PIXEL_ON, FALSE,screen);
+    if (fupdate==TRUE)
+        GLCD_update(screen);
+}
+
+void PCD8544MS::GLCD_drawchart(BYTE  x0, BYTE y0, BYTE w, BYTE h, BYTE unitx, BYTE unity,
+                               eRasterMode rMode, eChartMode cMode,eDrawMode dMode, int16_t * val, int size, int t,int screen)  {
+    int maxy;
+    int _scale=1;
+    int prescale=1;
+
+    signed char v1,v2;
+    char buffer[4];
+
+    if (size>w)
+        size=w;
+
+    // search maximum value to calculate scale
+    if (dMode==DRAW_OVERWRITE) {
+        maxy=0;
+        for (int i=0; i<size; i++) {
+            if (val[i]>maxy)
+                maxy=val[i];
+
+        }
+
+        if (maxy>h) {  //scale can be 1,2,5  *10i
+            prescale= ((maxy-1)/((h/unity)*unity));
+            _scale=1;
+            while (prescale>10) {
+                _scale=_scale*10;
+                prescale=prescale/10;
+            }
+            if (prescale>1)
+                _scale=_scale*5;
+            else if (prescale==1)
+                _scale  =_scale*2;
+
+
+        }
+        Scale=_scale;
+    }
+
+    if (dMode==DRAW_OVERWRITE) {
+        GLCD_drawrectangle(x0-11,y0-h,x0+w,y0+4+7,FILL_ON,PIXEL_OFF,FALSE,screen);
+        GLCD_drawline(x0,y0,x0,y0-h,PIXEL_ON,FALSE,screen);
+        GLCD_drawline(x0,y0,x0+w,y0,PIXEL_ON,FALSE,screen);
+
+        //drawrectangle(x0,y0-h,x0+w,y0,FILL_OFF,PIXEL_ON,FALSE);
+
+        for (int i=0; i<=h; i++) {
+            if ((i % unity) == 0) {
+                GLCD_drawpixel(x0-2,y0-i,PIXEL_ON,FALSE,screen);
+                //    drawpixel(x0+w+2,y0-i,PIXEL_ON,FALSE);
+
+                if (rMode==RASTER_ON) {
+                    for (int r=0; r<=w; r++) {
+                        if ((r % 2) ==0)
+                            GLCD_drawpixel(x0+r,y0-i,PIXEL_ON,FALSE,screen);
+                    }
+                }
+                // draw vertical axis labels
+
+                itostr(buffer,i*Scale);
+
+                //  pc_PCD8544.traceOut(" %i %s |",i*Scale,buffer);
+                GLCD_writeString(x0-11,y0-i+1,buffer,VERYSMALLFONT,PIXEL_OFF,DISPLAY_NORMAL,SPACE_NONE,FALSE,screen);
+
+            }
+            if ((i % 2) == 0) {
+                GLCD_drawpixel(x0-1,y0-i,PIXEL_ON,FALSE,screen);
+                //      drawpixel(x0+w+1,y0-i,PIXEL_ON,FALSE);
+            }
+        }
+
+        for (int i=0; i<=w; i++) {
+            if (((i+(t % unitx)) % unitx) == 0) {
+                GLCD_drawpixel(x0+i,y0+2,PIXEL_ON,FALSE,screen);
+
+                if (rMode==RASTER_ON) {
+                    for (int r=0; r<=h; r++) {
+                        if ((r % 2) ==0)
+                            GLCD_drawpixel(x0+i,y0-r,PIXEL_ON,FALSE,screen);
+                    }
+                }
+                if (((t-w+i)/unitx)>=0)
+                    snprintf(buffer,3,"%i",((t-w+i)/unitx));
+                else
+                    snprintf(buffer,3,"%i",24+((t-w+i)/unitx));
+
+                // pc_PCD8544.traceOut(" %i %s ",(t-w+i)/unitx,buffer);
+                GLCD_writeString(x0+i-3,y0+4,buffer,VERYSMALLFONT,PIXEL_OFF,DISPLAY_NORMAL,SPACE_NORMAL,FALSE,screen);
+            }
+            if ((i % 2) == 0) {
+                GLCD_drawpixel(x0+i,y0+1,PIXEL_ON,FALSE,screen);
+            }
+        }
+        //     update();
+    }
+
+    for (int i=0; i<size; i++) {
+        //   pc_PCD8544.traceOut(" %i ",val[i]);
+        v1 = val[i] / Scale;
+        if (v1>h)
+            v1=h;
+
+        if (i!=(size-1)) {
+            v2 = val[i+1] / Scale;
+            if (v2>h)
+                v2=h;
+        } else
+            v2=v1;
+
+
+        switch (cMode) {
+            case C_POINT: {
+                GLCD_drawpixel(x0+i,y0-v1,PIXEL_ON,FALSE,screen);
+                break;
+            }
+            case C_LINE: {
+                GLCD_drawline(x0+i,y0-v1,x0+i+1,y0-v2,PIXEL_ON,FALSE,screen);
+                break;
+            }
+            case C_VLINE: {
+                GLCD_drawline(x0+i,y0-v1,x0+i,y0,PIXEL_ON,FALSE,screen);
+                break;
+            }
+        }
+    }
+
+    GLCD_update(screen);
+}
+