1st Fork

Dependencies:   mbed QEI DmTftLibrary

Display/DisplayDriver.cpp

Committer:
lex9296
Date:
2022-02-15
Revision:
27:654100855f5c
Parent:
24:9f96fd6764d2

File content as of revision 27:654100855f5c:

/*
  ______                              _
 / _____)             _              | |
( (____  _____ ____ _| |_ _____  ____| |__
 \____ \| ___ |    (_   _) ___ |/ ___)  _ \
 _____) ) ____| | | || |_| ____( (___| | | |
(______/|_____)_|_|_| \__)_____)\____)_| |_|
    (C)2016 Semtech

Description: Display driver implementation

Maintainer: Gregory Cristian & Gilbert Menth
*/

#include "mbed.h"
#include "Eeprom.h"
#include "DisplayDriver.h"
#include "DmTftIli9341.h"
#include "DmTouch.h"
#include "DmTouchCalibration.h"

//If DISPLAY_INVERT is defined as 1 then the display will be inverted from its native orientation
#define DISPLAY_INVERT      1

#define MAX_GO_STRING       30
#define SPACE_ASCII         0x20
#define FONT_WIDTH          8

// DmTftIli9341( PinName cs, PinName dc, PinName mosi, PinName miso, PinName clk )
// DM_TFT28_105
DmTftIli9341 Tft( D10, D9, D11, D12, D13 );
DmTouch Touch( DmTouch::DM_TFT28_105, D9, D11, D12 );
DmTouchCalibration Calibration = DmTouchCalibration( &Tft, &Touch );

/* 
 * Used only to define pull-up on the CS lines
 */
DigitalInOut CsTouch( D4, PIN_OUTPUT, PullUp, 1 );
DigitalInOut CsDisplay( D10, PIN_OUTPUT, PullUp, 1 );
DigitalInOut CsSDCard( D8, PIN_OUTPUT, PullUp, 1 );
DigitalInOut CsFlash( D6, PIN_OUTPUT, PullUp, 1 );

MenuSettings_t MenuSettings;
char GoTmpString[MAX_GO_STRING];

static int BmpWidth;
static int BmpHeight;
static uint8_t BmpImageoffset;

static bool BmpReadHeader( uint8_t *thisBmp );
static uint16_t Read16( uint8_t *src );
static uint32_t Read32( uint8_t *src );
static void DrawBmpFromFlash( uint8_t *thisBmp, int x, int y );


void    DisplayDriverInit   (void) {
    Tft.init();
    Touch.init();

    DisplayDriverCalibrate();
    Tft.clearScreen();

    for (uint8_t i = 0; i < MAX_GO_STRING; i++)
        GoTmpString[i] = SPACE_ASCII;
}

// Calibrates the touch screen
void    DisplayDriverCalibrate  (void) {
    uint16_t x, y = 0;
    bool touched = false;

    if( Eeprom.EepromData.MenuSettings.ScreenCalibrated == false )
    {
        Tft.drawString( 5, 5, "Press and hold on cross" );
        Tft.drawString( 5, 25, "until it turns green. " );

        Point displayRefPoint[5];
        Point touchRefPoint[5];

        if( Calibration.getTouchReferencePoints( displayRefPoint, touchRefPoint,\
            Tft.width( ), Tft.height( ) ) )
        {
            CalibrationMatrix calibrationMatrix = \
                Calibration.calculateCalibrationMatrix( displayRefPoint, \
                                                        touchRefPoint );

            Touch.setCalibrationMatrix( calibrationMatrix );
            Tft.clearScreen( );
            Eeprom.EepromData.MenuSettings.Calibration.a = calibrationMatrix.a;
            Eeprom.EepromData.MenuSettings.Calibration.b = calibrationMatrix.b;
            Eeprom.EepromData.MenuSettings.Calibration.c = calibrationMatrix.c;
            Eeprom.EepromData.MenuSettings.Calibration.d = calibrationMatrix.d;
            Eeprom.EepromData.MenuSettings.Calibration.e = calibrationMatrix.e;
            Eeprom.EepromData.MenuSettings.Calibration.f = calibrationMatrix.f;
            Eeprom.EepromData.MenuSettings.ScreenCalibrated = true;
            EepromSaveSettings( SCREEN_DATA );
        }
        else
        {
            Tft.clearScreen( );
            Tft.drawString( 5, 5, "Calibration failed" );
            Tft.drawString( 5, 25, "Please try again." );
            delay( 2000 );

            Tft.clearScreen( );
            return;
        }
    }
    else
    {
        Touch.setCalibrationMatrix( Eeprom.EepromData.MenuSettings.Calibration );
        Tft.clearScreen( );
    }

    if( Touch.isTouched( ) )
    {
        Touch.readTouchData( x, y, touched );
        Calibration.drawCalibPoint( x, y );
    }
}

GraphObjectStatus_t GraphObjectDraw( GraphObject_t* goObject, uint8_t* source, \
                                     bool doFill, bool activeTouch)
{
    GraphObjectStatus_t status = GO_STATUS_NOERR;
    uint8_t maxChar;

    if( goObject == NULL )
    {
        return GO_STATUS_BAD_ARG;
    }
    if( goObject->Xpos + goObject->Width > SCREEN_WIDTH )
    {
        return GO_STATUS_BAD_COORD;
    }
    if( goObject->Ypos + goObject->Height > SCREEN_HEIGHT )
    {
        return GO_STATUS_BAD_COORD;
    }
    switch( goObject->Type )
    {
        case GO_TEXT:
            if( source == NULL )
            {
                status = GO_STATUS_BAD_ARG;
            }
            else
            {
                uint8_t i = 0;
                uint8_t j = 0;
                // max character in the object string
                maxChar = goObject->Width / FONT_WIDTH;
                Tft.setTextColor( goObject->BackColor, goObject->FrontColor );
                for( i = 0; i < maxChar; i++)
                {
                    if( *source != 0 )
                    {
                        Tft.drawChar( goObject->Xpos + j, goObject->Ypos, \
                                      ( char )*( source++ ), false );
                        j += FONT_WIDTH;
                    }
                    else
                    {
                        Tft.drawChar( goObject->Xpos + ( FONT_WIDTH * i ), \
                                      goObject->Ypos, SPACE_ASCII, false);
                    }
                }
                goObject->TouchActive = activeTouch;
            }
            break;

        case GO_RECTANGLE:
            Tft.drawRectangle( goObject->Xpos, goObject->Ypos, goObject->Xpos + \
                               goObject->Width - 1, goObject->Ypos + \
                               goObject->Height - 1, goObject->FrontColor );
            if( doFill )
            {
                Tft.fillRectangle( goObject->Xpos + 1, goObject->Ypos + 1, \
                                   goObject->Xpos + goObject->Width - 2, \
                                   goObject->Ypos + goObject->Height - 2, \
                                   goObject->FillColor );
            }
            goObject->TouchActive = activeTouch;
            break;

        case GO_CIRCLE:
            Tft.drawCircle( goObject->Xpos, goObject->Ypos, \
                            ( goObject->Height < goObject->Width ) ? \
                              ( goObject->Height / 2 ) : ( goObject->Width / 2 ), \
                            goObject->FrontColor );
            if( doFill )
            {
                Tft.fillCircle( goObject->Xpos, goObject->Ypos, \
                                ( goObject->Height < goObject->Width ) ? \
                                  ( goObject->Height / 2 ) - 1 : ( goObject->Width / 2 ) - 1, \
                                goObject->FillColor );
            }
            goObject->TouchActive = activeTouch;
            break;

        case GO_TRIANGLE:
            status = GO_STATUS_BAD_ARG;
            break;

        case GO_IMAGE:
            if( source == NULL )
            {
                status = GO_STATUS_BAD_ARG;
            }
            else
            {
                if( BmpReadHeader( goObject->Source ) )
                {
                    DrawBmpFromFlash( goObject->Source, goObject->Xpos, \
                                      goObject->Ypos );
                }
                else
                {
                    // draw a red rectangle with a line through, to show error
                    Tft.drawRectangle( goObject->Xpos, goObject->Ypos, \
                                       goObject->Xpos + goObject->Width - 1, \
                                       goObject->Ypos + goObject->Height - 1, \
                                       OBJECT_ERROR );
                    Tft.drawLine( goObject->Xpos, goObject->Ypos, goObject->Xpos + \
                                  goObject->Width - 1, goObject->Ypos + \
                                  goObject->Height - 1, OBJECT_ERROR );
                }
                goObject->TouchActive = activeTouch;
            }
            break;

        case GO_LINE:
            Tft.drawLine( goObject->Xpos, goObject->Ypos, goObject->Xpos + \
                                  goObject->Width - 1, goObject->Ypos + \
                                  goObject->Height - 1, goObject->FrontColor );
            break;

        default:
            status = GO_STATUS_BAD_ARG;
    }
    return status;
}

GraphObjectStatus_t GraphObjectClear( GraphObject_t* goObject, bool doFill )
{
    GraphObjectStatus_t status = GO_STATUS_NOERR;
    uint8_t maxChar;

    if( goObject == NULL )
    {
        return GO_STATUS_BAD_ARG;
    }
    if( goObject->Xpos + goObject->Width > SCREEN_WIDTH )
    {
        return GO_STATUS_BAD_COORD;
    }
    if( goObject->Ypos + goObject->Height > SCREEN_HEIGHT )
    {
        return GO_STATUS_BAD_COORD;
    }
    switch( goObject->Type )
    {
        case GO_TEXT:
            // max character in the object string
            maxChar = goObject->Width / FONT_WIDTH;
            GoTmpString[maxChar] = NULL;
            Tft.setTextColor( goObject->BackColor, goObject->FrontColor );
            Tft.drawString( goObject->Xpos, goObject->Ypos, GoTmpString );
            GoTmpString[maxChar] = SPACE_ASCII;
            goObject->TouchActive = false;
            break;

        case GO_RECTANGLE:
        case GO_IMAGE:
            if( doFill )
            {
                Tft.fillRectangle( goObject->Xpos, goObject->Ypos, \
                                   goObject->Xpos + goObject->Width - 1, \
                                   goObject->Ypos + goObject->Height - 1, \
                                   goObject->BackColor );
            }
            else
            {
                Tft.drawRectangle( goObject->Xpos, goObject->Ypos, goObject->Xpos + \
                                   goObject->Width - 1, goObject->Ypos + \
                                   goObject->Height - 1, goObject->BackColor );
            }
            goObject->TouchActive = false;
            break;

        case GO_CIRCLE:
            if( doFill )
            {
                Tft.fillCircle( goObject->Xpos, goObject->Ypos, \
                                ( goObject->Height < goObject->Width ) ? \
                                  ( goObject->Height / 2 ) : ( goObject->Width / 2 ), \
                                goObject->BackColor );
            }
            else
            {
                Tft.drawCircle( goObject->Xpos, goObject->Ypos, \
                                ( goObject->Height < goObject->Width ) ? \
                                  ( goObject->Height / 2 ) : ( goObject->Width / 2 ), \
                                goObject->BackColor );
            }
            goObject->TouchActive = false;
            break;

        case GO_TRIANGLE:
            status = GO_STATUS_BAD_ARG;
            goObject->TouchActive = false;
            break;

        case GO_LINE:
            Tft.drawLine( goObject->Xpos, goObject->Ypos, goObject->Xpos + \
                                  goObject->Width - 1, goObject->Ypos + \
                                  goObject->Height - 1, goObject->BackColor );
            goObject->TouchActive = false;
            break;

        default:
            status = GO_STATUS_BAD_ARG;
    }
    return status;
}

void DisplayDriverDrawLogo( uint8_t *thisBmp, uint8_t xPos, uint8_t yPos )
{
    if( BmpReadHeader( thisBmp ) )
    {
        DrawBmpFromFlash( thisBmp, xPos, yPos );
    }
}

void    TouchedXYT (uint16_t* x, uint16_t* y, bool* t) {
    uint16_t    ui16_x;
    uint16_t    ui16_y;
    bool        b_t;
    Touch.readTouchData (ui16_x,
                        ui16_y,
                        b_t);
                        
    *x = ui16_x;
    *y = ui16_y;
    *t = b_t;
}

GraphObjectStatus_t GraphObjectTouched( GraphObject_t* objects, \
                                        uint8_t objectsCount, \
                                        uint8_t* touchedObject)
{
    uint8_t objScan;
    uint16_t x, y = 0;
    bool touched = false;
    GraphObjectStatus_t status = GO_STATUS_BAD_COORD;

    if( Touch.isTouched( ) )
    {
        Touch.readTouchData( x, y, touched );

        if( touched == true )
        {
            for( objScan = 0; objScan < objectsCount; objScan++)
            {
                if( objects[objScan].TouchActive == true )
                {
                    if( ( y >= objects[objScan].Ypos ) && ( y <= ( objects[objScan].Ypos + objects[objScan].Height - 1 ) ) )
                    {
                        if( ( x >= objects[objScan].Xpos ) && ( x <= ( objects[objScan].Xpos + objects[objScan].Width - 1 ) ) )
                        {
                            *touchedObject = objects[objScan].Id;
                            status = GO_STATUS_NOERR;
                            break;      // return the first object match and no scan of other following objects
                        }
                    }
                }
            }
        }
    }

    return status;
}

static bool BmpReadHeader( uint8_t *thisBmp )
{
    uint16_t pos = 0;

    Read16( thisBmp );
    if( Read16( thisBmp ) != 0x4D42 )
    { // read magic byte
        return false;
    }
    pos += 2;

    // read file size
    pos += 4;
    pos += 4; // Skip creator bytes
    BmpImageoffset = Read32( thisBmp + pos );
    pos += 4;
    // read DIB header
    pos +=4;
    BmpWidth = Read32( thisBmp + pos );
    pos += 4;
    BmpHeight = Read32( thisBmp + pos );
    pos += 4;
    if( Read16( thisBmp + pos ) != 1 )
    {
        // number of color planes must be 1
        return false;
    }
    pos += 2;
    pos += 2;
    if( Read16( thisBmp + pos ) != 0 )
    {
        return false; // compression not supported!
    }
    pos += 2; // Should really be 2??
    return true;
}

// LITTLE ENDIAN!
static uint16_t Read16( uint8_t *src )
{
    uint16_t d;
    uint8_t b;
    b = *src;
    d = *( src + 1 );
    d <<= 8;
    d |= b;
    return d;
}

// LITTLE ENDIAN!
static uint32_t Read32( uint8_t *src )
{
    uint32_t d;
    uint16_t b;

    b = Read16( src );
    d = Read16( src + 2 );
    d <<= 16;
    d |= b;
    return d;
}

static void DrawBmpFromFlash( uint8_t *thisBmp, int xPos, int yPos )
{
    uint16_t pos = BmpImageoffset;
    uint16_t p;  // pixel
    uint8_t g;
    uint8_t b;
    int i, j; // line, column

    for( i = BmpHeight; i > 0; i-- )
    {
        for( j = 0; j < BmpWidth; j++ )
        {
            b = *( thisBmp + pos++ );
            g = *( thisBmp + pos++ );
            p = *( thisBmp + pos++ );

            p >>= 3;
            p <<= 6;

            g >>= 2;
            p |= g;
            p <<= 5;

            b >>= 3;
            p |= b;

            // write out the 16 bits of color
            Tft.setPixel( j + xPos, i + yPos, p );
        }
        pos += 1;
    }
}

void    LCM_ClearScreen (uint16_t color) {
    Tft.clearScreen (color);
}

void    LCM_DrawString  (uint16_t x, uint16_t y, const char *p) {
    Tft.drawString  (x, y, (char *)p);
}

void    LCM_SetTextColor    (uint16_t background, uint16_t foreground) {
    Tft.setTextColor    (background, foreground);
}

// LA:  Color RGB Component(s)
//      ======================
//
//  RED     0000 1000 0000 0000     min     0x0800  02048
//          1111 1000 0000 0000     max     0xf800  63488
//
//  GREEN   0000 0000 0010 0000     min     0x0020  00032   Real
//          0000 0111 1110 0000     max     0x07e0  02016
//
//  GREEN   0000 0000 0100 0000     min     0x0040  00064   This
//          0000 0111 1100 0000     max     0x07c0  01984
//
//  BLUE    0000 0000 0000 0001     min     0x0001  00001
//          0000 0000 0001 1111     max     0x001f  00031
//
//  La componente ROSSA ha  5 bit di escursione (0.. 31),
//  La componente VERDE ha  6 bit di escursione (0.. 63),   Normalmente
//  La componente VERDE ha  5 bit di escursione (0.. 31),   In qst applicazione
//  La componente BLU ha    5 bit di escursione (0.. 31),
//
//  Le componenti RGB di "Color" sono quindi scritte negli appropriati registri come segue:
//
//  writeReg(RED,   (Color & 0xf800) >> 11);
//  writeReg(GREEN, (Color & 0x07e0) >> 5);
//  writeReg(BLUE,  (Color & 0x001f));
//
uint16_t    Scale2RGBColor   (uint16_t R, uint16_t G, uint16_t B) {

    R = ((R& 0x1f)<< 11)& 0xf800;
    G = ((G& 0x1f)<< 6)& 0x07c0;
    B &=    0x001f;
    //
    return  (R+ G+ B);
}