Uses the same fonts as the SPI_TFT_ILI9341 Library (I have many, and a html/php font editor for that)

SPI_TFT_ILI9225.cpp

Committer:
JackB
Date:
2016-11-23
Revision:
0:cc1fb45bc3ad
Child:
1:8e447a4c8995

File content as of revision 0:cc1fb45bc3ad:

/*
****************                               ******************

Ported to mbed platform 
by Arman Safikhani  31 - 08-2015

Jack: Many thanks Arman!

Changed:
by Jack Berkhout 23-11-2016
- uses the same fonts as the SPI_TFT_ILI9341 Library (I have many, and a html/php editor for that)
- some code removed, some added, some changed
- the led backlight is using a PWM output, so it can be adjusted (0.0f = off - 1.0f = on)
- added formatted printf
- added claim as standard output on stream

* ***************                               ******************
*/

#include "SPI_TFT_ILI9225.h"
#define bitRead(value, bit) (((value) >> (bit)) & 0x01)

int font_color, x_font, y_font;
char highlight, fa_num;
int effect = 0, italic = 0;
unsigned int highlight_color;
/* Global Variables */
int x_text = 0, y_text = 0;
int x_base = 0;

// Constructor when using software SPI.  All output pins are configurable.
TFT_22_ILI9225::TFT_22_ILI9225(PinName sdi, PinName clk, PinName cs, PinName rs, PinName rst, PinName led, const char *name) :
    spi(sdi, NC, clk), _cs(cs), _rs(rs), _rst(rst), _led(led), Stream(name)
{
    spi.frequency(24000000); 
    spi.format(8, 0);

    // PWM output to control backlight
    _led.period_ms(10);

    // --- claim ---
    _row = 0;
    _column = 0;
    if (name == NULL) {
        _path = NULL;
    } else {
        _path = new char[strlen(name) + 2];
        sprintf(_path, "/%s", name);
    }
    // --- /claim ---
    
    init();
}

bool TFT_22_ILI9225::claim (FILE *stream) {
    if ( _path == NULL) {
        fprintf(stderr, "claim requires a name to be given in the instantioator of the TextDisplay instance!\r\n");
        return false;
    }
    if (freopen(_path, "w", stream) == NULL) {
        // Failed, should not happen
        return false;
    }
    // make sure we use line buffering
    setvbuf(stdout, NULL, _IOLBF, ILI9225_CHARS_PER_LINE);
    return true;
} 

void TFT_22_ILI9225::_orientCoordinates(uint16_t &x1, uint16_t &y1) {

    switch (_orientation) {
        case 0:  // ok
            break;
        case 1: // ok
            y1 = _maxY - y1 - 1;
            _swap(x1, y1);
            break;
        case 2: // ok
            x1 = _maxX - x1 - 1;
            y1 = _maxY - y1 - 1;
            break;
        case 3: // ok
            x1 = _maxX - x1 - 1;
            _swap(x1, y1);
            break;
    }
}

void TFT_22_ILI9225::_setWindowMax(void) {
    _setWindow(0, 0, maxX(), maxY());
}

void TFT_22_ILI9225::_setWindow(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1) {
    _orientCoordinates(x0, y0);
    _orientCoordinates(x1, y1);

    if (x1 < x0) _swap(x0, x1);
    if (y1 < y0) _swap(y0, y1);

    _writeRegister(ILI9225_HORIZONTAL_WINDOW_ADDR1, x1);
    _writeRegister(ILI9225_HORIZONTAL_WINDOW_ADDR2, x0);

    _writeRegister(ILI9225_VERTICAL_WINDOW_ADDR1, y1);
    _writeRegister(ILI9225_VERTICAL_WINDOW_ADDR2, y0);

    _writeRegister(ILI9225_RAM_ADDR_SET1, x0);
    _writeRegister(ILI9225_RAM_ADDR_SET2, y0);

    _writeCommand(0x00, 0x22);
}

void TFT_22_ILI9225::init()
{
    // Turn off backlight
    setBacklight(0.0f);

    // Initialization Code
    _rst = 0;// Pull the reset pin low to reset ILI9225
    wait_ms(10);
    _rst = 1;// Pull the reset pin high to release the ILI9225C from the reset status
    wait_ms(50);

    /* Start Initial Sequence */
    /* Set SS bit and direction output from S528 to S1 */
    _writeRegister(ILI9225_POWER_CTRL1, 0x0000); // Set SAP,DSTB,STB
    _writeRegister(ILI9225_POWER_CTRL2, 0x0000); // Set APON,PON,AON,VCI1EN,VC
    _writeRegister(ILI9225_POWER_CTRL3, 0x0000); // Set BT,DC1,DC2,DC3
    _writeRegister(ILI9225_POWER_CTRL4, 0x0000); // Set GVDD
    _writeRegister(ILI9225_POWER_CTRL5, 0x0000); // Set VCOMH/VCOML voltage
    wait_ms(40);

    // Power-on sequence
    _writeRegister(ILI9225_POWER_CTRL2, 0x0018); // Set APON,PON,AON,VCI1EN,VC
    _writeRegister(ILI9225_POWER_CTRL3, 0x6121); // Set BT,DC1,DC2,DC3
    _writeRegister(ILI9225_POWER_CTRL4, 0x006F); // Set GVDD   /*007F 0088 */
    _writeRegister(ILI9225_POWER_CTRL5, 0x495F); // Set VCOMH/VCOML voltage
    _writeRegister(ILI9225_POWER_CTRL1, 0x0800); // Set SAP,DSTB,STB
    wait_ms(10);
    _writeRegister(ILI9225_POWER_CTRL2, 0x103B); // Set APON,PON,AON,VCI1EN,VC
    wait_ms(50);

    _writeRegister(ILI9225_DRIVER_OUTPUT_CTRL, 0x011C); // set the display line number and display direction
    _writeRegister(ILI9225_LCD_AC_DRIVING_CTRL, 0x0100); // set 1 line inversion
    _writeRegister(ILI9225_ENTRY_MODE, 0x1030); // set GRAM write direction and BGR=1.
    _writeRegister(ILI9225_DISP_CTRL1, 0x0000); // Display off
    _writeRegister(ILI9225_BLANK_PERIOD_CTRL1, 0x0808); // set the back porch and front porch
    _writeRegister(ILI9225_FRAME_CYCLE_CTRL, 0x1100); // set the clocks number per line
    _writeRegister(ILI9225_INTERFACE_CTRL, 0x0000); // CPU interface
    _writeRegister(ILI9225_OSC_CTRL, 0x0D01); // Set Osc  /*0e01*/
    _writeRegister(ILI9225_VCI_RECYCLING, 0x0020); // Set VCI recycling
    _writeRegister(ILI9225_RAM_ADDR_SET1, 0x0000); // RAM Address
    _writeRegister(ILI9225_RAM_ADDR_SET2, 0x0000); // RAM Address

                                                   /* Set GRAM area */
    _writeRegister(ILI9225_GATE_SCAN_CTRL, 0x0000);
    _writeRegister(ILI9225_VERTICAL_SCROLL_CTRL1, 0x00DB);
    _writeRegister(ILI9225_VERTICAL_SCROLL_CTRL2, 0x0000);
    _writeRegister(ILI9225_VERTICAL_SCROLL_CTRL3, 0x0000);
    _writeRegister(ILI9225_PARTIAL_DRIVING_POS1, 0x00DB);
    _writeRegister(ILI9225_PARTIAL_DRIVING_POS2, 0x0000);
    _writeRegister(ILI9225_HORIZONTAL_WINDOW_ADDR1, 0x00AF);
    _writeRegister(ILI9225_HORIZONTAL_WINDOW_ADDR2, 0x0000);
    _writeRegister(ILI9225_VERTICAL_WINDOW_ADDR1, 0x00DB);
    _writeRegister(ILI9225_VERTICAL_WINDOW_ADDR2, 0x0000);

    /* Set GAMMA curve */
    _writeRegister(ILI9225_GAMMA_CTRL1, 0x0000);
    _writeRegister(ILI9225_GAMMA_CTRL2, 0x0808);
    _writeRegister(ILI9225_GAMMA_CTRL3, 0x080A);
    _writeRegister(ILI9225_GAMMA_CTRL4, 0x000A);
    _writeRegister(ILI9225_GAMMA_CTRL5, 0x0A08);
    _writeRegister(ILI9225_GAMMA_CTRL6, 0x0808);
    _writeRegister(ILI9225_GAMMA_CTRL7, 0x0000);
    _writeRegister(ILI9225_GAMMA_CTRL8, 0x0A00);
    _writeRegister(ILI9225_GAMMA_CTRL9, 0x0710);
    _writeRegister(ILI9225_GAMMA_CTRL10, 0x0710);

    _writeRegister(ILI9225_DISP_CTRL1, 0x0012);
    wait_ms(50);
    _writeRegister(ILI9225_DISP_CTRL1, 0x1017);

    cls();
    linespacing(0);
    setBacklight(1.0f);
    setOrientation(ILI9225_LANDSCAPE_R);
    foreground(COLOR_WHITE);
    background(COLOR_BLACK);
}

void TFT_22_ILI9225::cls() {
    setBacklightOff();
    _setWindowMax();
    _rs = 1;
    _cs = 0;
    for (uint16_t i = width() * height(); i > 0; i--) {
        spi.write(0x00);
        spi.write(0x00);
    }
    _cs = 1;
    setBacklightOn();
    gotoxy(0, 0);
}

void TFT_22_ILI9225::fill(uint16_t color)
{
    fillRectangle(0, 0, maxX(), maxY(), color);
}

void TFT_22_ILI9225::invert(bool flag) {
    _writeCommand(0x00, flag ? ILI9225C_INVON : ILI9225C_INVOFF);
}

void TFT_22_ILI9225::setBacklight(double brightness) {
    // PWM output to control backlight
    _brightness = brightness;
    _led.write(pow(brightness, 2)); // power(x, 2): For the eye better brightness response
}

void TFT_22_ILI9225::setBacklightOff(void) {
    _led.write(0.0f);
}

void TFT_22_ILI9225::setBacklightOn(void) {
    setBacklight(_brightness);
}

void TFT_22_ILI9225::setDisplay(bool flag) {
    if (flag) {
        _writeRegister(0x00ff, 0x0000);
        _writeRegister(ILI9225_POWER_CTRL1, 0x0000);
        wait_ms(50);
        _writeRegister(ILI9225_DISP_CTRL1, 0x1017);
        wait_ms(200);
    }
    else {
        _writeRegister(0x00ff, 0x0000);
        _writeRegister(ILI9225_DISP_CTRL1, 0x0000);
        wait_ms(50);
        _writeRegister(ILI9225_POWER_CTRL1, 0x0003);
        wait_ms(200);
    }
}

void TFT_22_ILI9225::setOrientation(uint8_t orientation) {

    _orientation = orientation % 4;

    switch (_orientation) {
    case 0:
        _maxX = ILI9225_LCD_WIDTH;
        _maxY = ILI9225_LCD_HEIGHT;
        break;
    case 1:
        _maxX = ILI9225_LCD_HEIGHT;
        _maxY = ILI9225_LCD_WIDTH;
        break;
    case 2:
        _maxX = ILI9225_LCD_WIDTH;
        _maxY = ILI9225_LCD_HEIGHT;
        break;
    case 3:
        _maxX = ILI9225_LCD_HEIGHT;
        _maxY = ILI9225_LCD_WIDTH;
        break;
    }
}

uint8_t TFT_22_ILI9225::getOrientation() {
    return _orientation;
}

void TFT_22_ILI9225::drawRectangle(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t color) {
    drawLine(x1, y1, x1, y2, color);
    drawLine(x1, y1, x2, y1, color);
    drawLine(x1, y2, x2, y2, color);
    drawLine(x2, y1, x2, y2, color);
}

void TFT_22_ILI9225::fillRectangle(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t color) {

    _setWindow(x1, y1, x2, y2);
    _startData();
    for (uint16_t t = (y2 - y1 + 1) * (x2 - x1 + 1); t > 0; t--) {
        _writeData(color);
    }
    _endData();
}

void TFT_22_ILI9225::drawCircle(uint16_t x0, uint16_t y0, uint16_t r, uint16_t color) {

    int16_t f = 1 - r;
    int16_t ddF_x = 1;
    int16_t ddF_y = -2 * r;
    int16_t x = 0;
    int16_t y = r;

    drawPixel(x0, y0 + r, color);
    drawPixel(x0, y0 - r, color);
    drawPixel(x0 + r, y0, color);
    drawPixel(x0 - r, y0, color);

    while (x < y) {
        if (f >= 0) {
            y--;
            ddF_y += 2;
            f += ddF_y;
        }
        x++;
        ddF_x += 2;
        f += ddF_x;

        drawPixel(x0 + x, y0 + y, color);
        drawPixel(x0 - x, y0 + y, color);
        drawPixel(x0 + x, y0 - y, color);
        drawPixel(x0 - x, y0 - y, color);
        drawPixel(x0 + y, y0 + x, color);
        drawPixel(x0 - y, y0 + x, color);
        drawPixel(x0 + y, y0 - x, color);
        drawPixel(x0 - y, y0 - x, color);
    }
}

void TFT_22_ILI9225::fillCircle(uint8_t x0, uint8_t y0, uint8_t radius, uint16_t color) {

    int16_t f = 1 - radius;
    int16_t ddF_x = 1;
    int16_t ddF_y = -2 * radius;
    int16_t x = 0;
    int16_t y = radius;

    while (x < y) {
        if (f >= 0) {
            y--;
            ddF_y += 2;
            f += ddF_y;
        }
        x++;
        ddF_x += 2;
        f += ddF_x;

        drawLine(x0 + x, y0 + y, x0 - x, y0 + y, color); // bottom
        drawLine(x0 + x, y0 - y, x0 - x, y0 - y, color); // top
        drawLine(x0 + y, y0 - x, x0 + y, y0 + x, color); // right
        drawLine(x0 - y, y0 - x, x0 - y, y0 + x, color); // left
    }
    fillRectangle(x0 - x, y0 - y, x0 + x, y0 + y, color);
}

void TFT_22_ILI9225::drawLine(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t color) {

    // Classic Bresenham algorithm
    int16_t steep = abs(y2 - y1) > abs(x2 - x1);
    int16_t dx, dy;

    if (steep) {
        _swap(x1, y1);
        _swap(x2, y2);
    }

    if (x1 > x2) {
        _swap(x1, x2);
        _swap(y1, y2);
    }

    dx = x2 - x1;
    dy = abs(y2 - y1);

    int16_t err = dx / 2;
    int16_t ystep;

    if (y1 < y2) ystep = 1;
    else ystep = -1;


    for (; x1 <= x2; x1++) {
        if (steep) drawPixel(y1, x1, color);
        else       drawPixel(x1, y1, color);

        err -= dy;
        if (err < 0) {
            y1 += ystep;
            err += dx;
        }
    }
}

void TFT_22_ILI9225::drawPixel(uint16_t x1, uint16_t y1, uint16_t color) {

    if ((x1 >= _maxX) || (y1 >= _maxY)) return;

    _setWindow(x1, y1, x1 + 1, y1 + 1);
    _orientCoordinates(x1, y1);
    _startData();
    _writeData(color);
    _endData();
}

uint16_t TFT_22_ILI9225::maxX(void) {
    return _maxX - 1;
}

uint16_t TFT_22_ILI9225::maxY(void) {
    return _maxY - 1;
}

uint16_t TFT_22_ILI9225::width(void) {
    return _maxX;
}

uint16_t TFT_22_ILI9225::height(void) {
    return _maxY;
}

uint16_t TFT_22_ILI9225::setColor(uint8_t red8, uint8_t green8, uint8_t blue8) {
    // rgb16 = red5 green6 blue5
    return (red8 >> 3) << 11 | (green8 >> 2) << 5 | (blue8 >> 3);
}

void TFT_22_ILI9225::splitColor(uint16_t rgb, uint8_t &red, uint8_t &green, uint8_t &blue) {
    // rgb16 = red5 green6 blue5
    
    red = (rgb & 0xF800) >> 11 << 3;
    green = (rgb & 0x7E0) >> 5 << 2;
    blue = (rgb & 0x1F) << 3;
}

void TFT_22_ILI9225::_swap(uint16_t &a, uint16_t &b) {
    uint16_t w = a;
    a = b;
    b = w;
}

void TFT_22_ILI9225::_writeCommand(uint8_t HI, uint8_t LO) {
    _rs = 0;
    _cs = 0;
    spi.write(HI);
    spi.write(LO);
    _cs = 1;
}

void TFT_22_ILI9225::_writeData(uint16_t data) {
    spi.write(data >> 8);
    spi.write(data & 0xff);
//    spi.write(data);
}

void TFT_22_ILI9225::_startData(void) {
    _rs = 1;
    _cs = 0;
//    spi.format(16, 0);    // New mbed library can't use 16 bit spi anymore on this platform
}

void TFT_22_ILI9225::_endData(void) {
    _cs = 1;
//    spi.format(8, 0);
}

void TFT_22_ILI9225::_writeRegister(uint16_t reg, uint16_t data) {
    _writeCommand(reg >> 8, reg & 0xff);
    _startData();
    _writeData(data);
    _endData();
}

void TFT_22_ILI9225::drawTriangle(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t x3, uint16_t y3, uint16_t color) {
    drawLine(x1, y1, x2, y2, color);
    drawLine(x2, y2, x3, y3, color);
    drawLine(x3, y3, x1, y1, color);
}

void TFT_22_ILI9225::fillTriangle(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t x3, uint16_t y3, uint16_t color) {

    uint16_t a, b, y, last;

    // Sort coordinates by Y order (y3 >= y2 >= y1)
    if (y1 > y2) {
        _swap(y1, y2); _swap(x1, x2);
    }
    if (y2 > y3) {
        _swap(y3, y2); _swap(x3, x2);
    }
    if (y1 > y2) {
        _swap(y1, y2); _swap(x1, x2);
    }

    if (y1 == y3) { // Handle awkward all-on-same-line case as its own thing
        a = b = x1;
        if (x2 < a)      a = x2;
        else if (x2 > b) b = x2;
        if (x3 < a)      a = x3;
        else if (x3 > b) b = x3;
        drawLine(a, y1, b, y1, color);
        return;
    }

    uint16_t    dx11 = x2 - x1,
        dy11 = y2 - y1,
        dx12 = x3 - x1,
        dy12 = y3 - y1,
        dx22 = x3 - x2,
        dy22 = y3 - y2,
        sa = 0,
        sb = 0;

    // For upper part of triangle, find scanline crossings for segments
    // 0-1 and 0-2.  If y2=y3 (flat-bottomed triangle), the scanline y2
    // is included here (and second loop will be skipped, avoiding a /0
    // error there), otherwise scanline y2 is skipped here and handled
    // in the second loop...which also avoids a /0 error here if y1=y2
    // (flat-topped triangle).
    if (y2 == y3) last = y2;   // Include y2 scanline
    else          last = y2 - 1; // Skip it

    for (y = y1; y <= last; y++) {
        a = x1 + sa / dy11;
        b = x1 + sb / dy12;
        sa += dx11;
        sb += dx12;
        /* longhand:
        a = x1 + (x2 - x1) * (y - y1) / (y2 - y1);
        b = x1 + (x3 - x1) * (y - y1) / (y3 - y1);
        */
        if (a > b) _swap(a, b);
        drawLine(a, y, b, y, color);
    }

    // For lower part of triangle, find scanline crossings for segments
    // 0-2 and 1-2.  This loop is skipped if y2=y3.
    sa = dx22 * (y - y2);
    sb = dx12 * (y - y1);
    for (; y <= y3; y++) {
        a = x2 + sa / dy22;
        b = x1 + sb / dy12;
        sa += dx22;
        sb += dx12;
        /* longhand:
        a = x2 + (x3 - x2) * (y - y2) / (y3 - y2);
        b = x1 + (x3 - x1) * (y - y1) / (y3 - y1);
        */
        if (a > b) _swap(a, b);
        drawLine(a, y, b, y, color);
    }
}

void TFT_22_ILI9225::setFont(unsigned char* f) {
    font = f;
}

int TFT_22_ILI9225::putc(int value)
{
    if (value == '\n') {    // new line
        char_x = 0;
        char_y = char_y + (font[FONT_VERT] + char_line_spacing);
        if (char_y >= height() - (font[FONT_VERT] + char_line_spacing)) {
            char_y = 0;
        }
        return value;
    }
    if ((value < 32) || (value > 127)) {
        return value;
    }
    character(char_x, char_y, value);
    return value;
}

void TFT_22_ILI9225::character(int x, int y, int c)
{
    unsigned int hor, vert, offset, bpl, 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[FONT_LENGTH];         // bytes / char
    hor    = font[FONT_HORZ];           // get hor size of font
    vert   = font[FONT_VERT];           // get vert size of font
    bpl    = font[FONT_BYTES_VERT];     // bytes per line

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

    zeichen = &font[((c -32) * offset) + 4]; // start of char bitmap
    w = zeichen[0];                          // width of actual char
    _startData();

    switch (_orientation) {
        case 0:
            // Portrait
            for (int j=0; j < vert; j++) {  //  vert line
                for (int i=0; i<hor; i++) {   //  horz line
                    z =  zeichen[bpl * i + ((j & 0xF8) >> 3)+1];
                    b = 1 << (j & 0x07);
                    if (( z & b ) == 0x00) {
                        spi.write(_background >> 8);
                        spi.write(_background & 0xff);
                    } else {
                        spi.write(_foreground >> 8);
                        spi.write(_foreground & 0xff);
                    }
                }
            }
            break;
        case 1:
            // Landscape
            for (int i=0; i<hor; i++) {   //  horz line
                for (int j=vert-1; j>=0; j--) {  //  vert line
                    z =  zeichen[bpl * i + ((j & 0xF8) >> 3)+1];
                    b = 1 << (j & 0x07);
                    if (( z & b ) == 0x00) {
                        spi.write(_background >> 8);
                        spi.write(_background & 0xff);
                    } else {
                        spi.write(_foreground >> 8);
                        spi.write(_foreground & 0xff);
                    }
                }
            }
            break;
        case 2:
            // Portrait
            for (int j=vert-1; j>=0; j--) {  //  vert line
                for (int i=hor-1; i>=0; i--) {   //  horz line
                    z =  zeichen[bpl * i + ((j & 0xF8) >> 3)+1];
                    b = 1 << (j & 0x07);
                    if (( z & b ) == 0x00) {
                        spi.write(_background >> 8);
                        spi.write(_background & 0xff);
                    } else {
                        spi.write(_foreground >> 8);
                        spi.write(_foreground & 0xff);
                    }
                }
            }
            break;
        case 3:
            // Landscape
            for (int i=hor-1; i>= 0; i--) {   //  horz line
                for (int j=0; j<vert; j++) {  //  vert line
                    z =  zeichen[bpl * i + ((j & 0xF8) >> 3)+1];
                    b = 1 << (j & 0x07);
                    if (( z & b ) == 0x00) {
                        spi.write(_background >> 8);
                        spi.write(_background & 0xff);
                    } else {
                        spi.write(_foreground >> 8);
                        spi.write(_foreground & 0xff);
                    }
                }
            }
            break;
    }
    
    _endData();
    _setWindowMax();
    if ((w + 2) < hor) {                   // x offset to next char
        char_x += w + 2;
    } else char_x += hor;
}
        
void TFT_22_ILI9225::foreground(uint16_t colour) {
    _foreground = colour;
}

void TFT_22_ILI9225::background(uint16_t colour) {
    _background = colour;
}

void TFT_22_ILI9225::locate(int x, int y)
{
    char_x = x;
    char_y = y;
}

void TFT_22_ILI9225::gotoxy(int x, int y)
{
    char_x = x * font[FONT_HORZ];
    char_y = y * (font[FONT_VERT] + char_line_spacing);
}

void TFT_22_ILI9225::home(void)
{
    gotoxy(0, 0);
}

void TFT_22_ILI9225::linespacing(int line_spacing)
{
    char_line_spacing = line_spacing;
}

int TFT_22_ILI9225::columns()
{
    return width() / font[FONT_HORZ];
}

int TFT_22_ILI9225::rows()
{
    return height() / font[FONT_VERT];
}

//----------------------------------------------------------------------------------------------------
//************************************* ECA 2.8 inch LCD Module **************************************
//----------------------------------------------------------------------------------------------------
// Description  : Draws a beveled figure on the screen. 
// Input        : x0, y0 - coordinate position of the upper left center
//                  : x1, y1 - coordinate position of the lower right center
//              : rad    - defines the redius of the circle,
//              : fill   - fill yes or no
//----------------------------------------------------------------------------------------------------
void TFT_22_ILI9225::roundRectangle(int x0, int y0, int x1, int y1, int rad, bool fill, int color)
{
    signed int a, b, P;

    a = 0;                      // increment by 1
    b = rad;                // decrement by 1 using P
    P = 1 - rad;


    if (fill)
    {
        fillRectangle(x0, y0 + rad, x1, y1 - rad, color);

        do
        {
            fillRectangle(x0 - a + rad, y0 - b + rad, a + x1 - rad, y0 - b + rad, color);   // 8 --> 1
            fillRectangle(x0 - b + rad, y0 - a + rad, b + x1 - rad, y0 - a + rad, color);   // 7 --> 2
            fillRectangle(x0 - b + rad, a + y1 - rad, b + x1 - rad, a + y1 - rad, color);   // 6 --> 3
            fillRectangle(x0 - a + rad, b + y1 - rad, a + x1 - rad, b + y1 - rad, color);   // 5 --> 4

            if (P < 0)
                P += 3 + 2 * a++;
            else
                P += 5 + 2 * (a++ - b--);

        } while (a <= b);
    } //fill
    else
    {
        fillRectangle(x0 + rad, y0, x1 - rad, y0, color);   // top
        fillRectangle(x0 + rad, y1, x1 - rad, y1, color);   // bottom
        fillRectangle(x0, y0 + rad, x0, y1 - rad, color);   // left
        fillRectangle(x1, y0 + rad, x1, y1 - rad, color);   // right

        do
        {
            drawPixel(a + x1 - rad, y0 - b + rad, color);   // `````` Segment 1
            drawPixel(b + x1 - rad, y0 - a + rad, color);   // `````` Segment 2

            drawPixel(b + x1 - rad, a + y1 - rad, color);   // `````` Segment 3
            drawPixel(a + x1 - rad, b + y1 - rad, color);   // `````` Segment 4

            drawPixel(x0 - a + rad, b + y1 - rad, color);   // `````` Segment 5
            drawPixel(x0 - b + rad, a + y1 - rad, color);   // `````` Segment 6

            drawPixel(x0 - b + rad, y0 - a + rad, color);   // `````` Segment 7
            drawPixel(x0 - a + rad, y0 - b + rad, color);   // `````` Segment 8

            if (P < 0)
                P += 3 + 2 * a++;
            else
                P += 5 + 2 * (a++ - b--);
        } while (a <= b);
    } //no fill
}   //RoundRectangle

//----------------------------------------------------------------------------------------------------
//************************************* ECA 2.8 inch LCD Module **************************************
//----------------------------------------------------------------------------------------------------
// Make an ascii string from an unicode string 
//----------------------------------------------------------------------------------------------------

void TFT_22_ILI9225::unicode2ascii(char *uni_str, char *ascii_str)
{
    int counter = 0;
    int Uch = 0;
    char chl, chh;


    while (*uni_str)
    {
        chl = *uni_str++;
        chh = *uni_str++;

        Uch = 0;
        Uch = ((Uch | chh) << 8) | chl;

        if (Uch > 1574 && Uch < 1591)
            *(ascii_str + counter) = (char)(Uch - 1376);
        else if (Uch > 1590 && Uch < 1595)
            *(ascii_str + counter) = (char)(Uch - 1375);
        else if (Uch > 1600 && Uch < 1603)
            *(ascii_str + counter) = (char)(Uch - 1380);
        else if (Uch == 1705)
            *(ascii_str + counter) = (char)(Uch - 1482);
        else if (Uch == 1604)
            *(ascii_str + counter) = (char)(Uch - 1379);
        else if (Uch > 1604 && Uch < 1609)
            *(ascii_str + counter) = (char)(Uch - 1378);
        else if (Uch == 1740)
            *(ascii_str + counter) = (char)(Uch - 1503);
        else if (Uch == 1574)
            *(ascii_str + counter) = (char)(Uch - 1381);
        else if (Uch == 1662)
            *(ascii_str + counter) = (char)(Uch - 1533);
        else if (Uch == 1670)
            *(ascii_str + counter) = (char)(Uch - 1529);
        else if (Uch == 1688)
            *(ascii_str + counter) = (char)(Uch - 1546);
        else if (Uch == 1711)
            *(ascii_str + counter) = (char)(Uch - 1567);
        else if (Uch == 1570)
            *(ascii_str + counter) = (char)(Uch - 1376);
        else if (Uch > 1631 && Uch < 1642)
            *(ascii_str + counter) = (char)(Uch - 1584);
        else if (Uch == 65536)
            *(ascii_str + counter) = NULL;
        else
            *(ascii_str + counter) = (char)Uch;


        counter++;

    }
    *(ascii_str + counter) = NULL;

}