Touch screen drivers control dashboard for miniature locomotive. Features meters for speed, volts, power. Switches for lights, horns. Drives multiple STM3_ESC brushless motor controllers for complete brushless loco system as used in "The Brute" - www.jons-workshop.com

Dependencies:   TS_DISCO_F746NG mbed Servo LCD_DISCO_F746NG BSP_DISCO_F746NG QSPI_DISCO_F746NG AsyncSerial FastPWM

graphics.cpp

Committer:
JonFreeman
Date:
2019-03-04
Revision:
14:6bcec5ac21ca
Parent:
12:a25bdf135348

File content as of revision 14:6bcec5ac21ca:

#include "mbed.h"
#include "TS_DISCO_F746NG.h"
#include "LCD_DISCO_F746NG.h"
#include "Electric_Loco.h"


extern  LCD_DISCO_F746NG    lcd;
extern  TS_DISCO_F746NG     touch_screen;
extern  Serial pc;

/*
moving_coil_meter   Voltmeter   (   LCD_COLOR_BLACK,    //  Frame / body colour
                                    LCD_COLOR_WHITE,    //  Dial face colour
                                    LCD_COLOR_RED,      //  Moving needle colour
                                    LCD_COLOR_BLUE,     //  Text colour for Units e.g. 'V' and e.g. '32.7'
                                    LCD_COLOR_MAGENTA,  //  Scale graduations colour
                                    VOLTMETER_X,        //  X co-ord, centre of meter
                                    VOLTMETER_Y,        //  Y co-ord, centre of meter
                                    V_A_SIZE,           //  Meter is square with rounded corners. This is meter dial face radius
                                    22.0,               //  Scale not limited to e.g. 0 to 10. This is reading at anti-clock limit
                                    59.0,               //  This is reading at full scale deflection
                                    1.25 * PI,          //  Angle of needle at anti-clockwise limit
                                    -0.25 * PI ,        //  Angle of needle at full scale deflection (clockwise max)
                                    30,                 //  Number of scale graduation marks drwan
                                    "V",                //  Text for Units, e.g. 'V' or 'MPH'
                                    ONE_DP,             //  NO_DPS or ONE_DP - supports only no decimal places or one
                                    false) ;            //  true to show '+' or '-', false to supress sign display
*/
/*moving_coil_meter   Voltmeter   (   LCD_COLOR_BLACK, LCD_COLOR_WHITE, LCD_COLOR_RED, LCD_COLOR_BLUE, LCD_COLOR_MAGENTA,
                                    VOLTMETER_X, VOLTMETER_Y, V_A_SIZE, 22.0, 61.0, 1.25 * PI, -0.25 * PI , 20, "V", ONE_DP, false),  
                    Powermeter  (   LCD_COLOR_BLACK, LCD_COLOR_WHITE, LCD_COLOR_RED, LCD_COLOR_BLUE, LCD_COLOR_BLUE,
                                    AMMETER_X, AMMETER_Y, V_A_SIZE, -1400.0, 1400.0, 1.25 * PI, -0.25 * PI , 14, "Watt", NO_DPS, false),    
                    Speedo      (   SPEEDO_BODY_COLOUR, SPEEDO_DIAL_COLOUR, LCD_COLOR_RED, SPEEDO_TEXT_COLOUR, LCD_COLOR_BLACK,
                                    SPEEDO_X, SPEEDO_Y, SPEEDO_SIZE, 0.0, 12.0, 1.25 * PI, -0.25 * PI , 12, "MPH", ONE_DP, false);     //  3 instances of moving coil meter graphic

*/



void    displaytext    (int x, int y, const int font, char * txt)   ;

extern  uint32_t    odometer_out  ()    ;
void    rewrite_odometer    ()  {
    char    dist[20];
    sprintf (dist, "%06dm", odometer_out());   //  12th June 2018 changed 05 to 06 to allow correct display of tot distance > 99999 metres
    lcd.SetTextColor    (LCD_COLOR_BLACK);
    displaytext (241, 224, 2, dist);
}

struct  rect    {   struct point a, b; }   ;

struct  button_specs  {
    struct  rect    area;
    int border_colour,  body_colour;
    bool    in_use, pressed;//, released;
    char txt1[12];
    char txt2[12];
}   ;

struct  button_specs   button[NUMOF_BUTTONS];

int get_button_press    (struct point & pt) ;
int get_but_p   (int x, int y)
{
    struct  point   p;
    p.x = x;
    p.y = y;
    return  get_button_press    (p);
}

/**
void    read_keypresses    (struct ky_bd & a)
Sets values in struct ky_bd, containing :
        struct  ky_bd   {   int count,  slider_y; keystr key[MAX_TOUCHES + 1];   bool  sli;   }  ;
            struct  keystr  {   int keynum; int x;  int y;  }   ;
    sets a.count to number of fingers found pressing buttons
    fills a.key[].keynum with list of 'a.count' button return codes
    fills corresponding a.key[].x and a.key[].y with finger coordinates
    if button is SLIDER_BUTTON
        sets a.sli true else sets false
        sets a.slider_y with new slider y coordinate - 0 at top
*/
void    read_keypresses    (struct ky_bd & a)
{
    int x;
    a.count = 0;
    a.sli   = false;
    for (x = 0; x < MAX_TOUCHES; x++)
        a.key[x].keynum = -1;
    int touches, but;
    TS_StateTypeDef TS_State;
    touch_screen.GetState(&TS_State);
    touches = TS_State.touchDetected;
    for (int h = 0; h < touches; h++)   {
        but = get_but_p  (TS_State.touchX[h], TS_State.touchY[h]);
        if  (but > - 1) {
            a.key[a.count].keynum = but;
            a.key[a.count].x     = TS_State.touchX[h];
            a.key[a.count].y     = TS_State.touchY[h];
            if  (but == SLIDER_BUTTON) {
                a.sli   = true;
                a.slider_y  = a.key[a.count].y;
            }
            a.count++;
        }
    }
}


void    displaytext    (int x, int y, char * txt)
{
    lcd.DisplayStringAt(x, y, (uint8_t *)txt, LEFT_MODE);
}

void    displaytext    (int x, int y, const int font, char * txt)
{
    sFONT * const fp[] = {&Font8, &Font12, &Font16, &Font20, &Font24};
    lcd.SetFont(fp[font]);
    displaytext (x, y, txt);
}

void    displaytext    (int x, int y, const int font, uint32_t BCol, uint32_t TCol, char * txt)
{
    uint32_t otc, obc;
    otc = lcd.GetTextColor();
    obc = lcd.GetBackColor();
    lcd.SetTextColor(TCol);
    lcd.SetBackColor(BCol);
    displaytext (x, y, font, txt);
    lcd.SetTextColor(otc);
    lcd.SetBackColor(obc);
}

void    draw_button (struct button_specs & bu)
{
    int oldbgcolour;
    lcd.SetTextColor    (bu.body_colour);
    lcd.FillRect(bu.area.a.x + 2, bu.area.a.y + 2, bu.area.b.x - bu.area.a.x - 2, bu.area.b.y - bu.area.a.y - 2);   //, bu.body_colour);
    oldbgcolour = lcd.GetBackColor();
    lcd.SetBackColor(bu.body_colour);
    lcd.SetTextColor(LCD_COLOR_BLACK);
    if  (strlen(bu.txt2) == 0)   {
        displaytext     (bu.area.a.x + 4, bu.area.a.y + 14, 4, bu.txt1); //  largest font 4
    } else    {
        displaytext     (bu.area.a.x + 4, bu.area.a.y + 4, 3, bu.txt1); //  not so large font 3
        displaytext     (bu.area.a.x + 4, bu.area.a.y + 26, bu.txt2);
    }
    lcd.SetBackColor(LCD_COLOR_BLACK);
    lcd.SetTextColor(bu.border_colour);
    lcd.DrawRect(bu.area.a.x, bu.area.a.y, bu.area.b.x - bu.area.a.x, bu.area.b.y - bu.area.a.y);   //, bu.border_colour);
    lcd.DrawRect(bu.area.a.x + 1, bu.area.a.y + 1, bu.area.b.x - bu.area.a.x - 1, bu.area.b.y - bu.area.a.y - 1);   //, bu.border_colour);
    lcd.SetBackColor(oldbgcolour);
}

void    draw_button_hilight     (int but, int colour)
{
    if  (but < 0 || but > NUMOF_BUTTONS)    {
        pc.printf   ("Button out of range in draw_button_hilight %d\r\n", but)  ;
    } else    {
        struct   button_specs * bu = &button[but];
        int oldbgcolour = lcd.GetBackColor();//, minx, miny, maxx, maxy;
        lcd.SetTextColor(colour);
        lcd.DrawRect(bu->area.a.x - 1, bu->area.a.y - 1, bu->area.b.x - bu->area.a.x + 2, bu->area.b.y - bu->area.a.y + 2);
        lcd.DrawRect(bu->area.a.x - 2, bu->area.a.y - 2, bu->area.b.x - bu->area.a.x + 4, bu->area.b.y - bu->area.a.y + 4);
        lcd.DrawRect(bu->area.a.x - 2, bu->area.a.y - 3, bu->area.b.x - bu->area.a.x + 5, bu->area.b.y - bu->area.a.y + 6);
        lcd.SetBackColor(oldbgcolour);
    }
}

void    draw_button (struct button_specs & bu, int body_colour)
{
    bu.body_colour = body_colour;
    draw_button (bu);
}

void    setup_button    (struct button_specs & bu, int x1, int y1, int dx, int dy, int bord, int body, char * txt1, char * txt2)
{
    static const int margin = 3;
    int xsize = lcd.GetXSize();
    int ysize = lcd.GetXSize();
    int x2 = x1 + dx, y2 = y1 + dy;
    if  (x1 < margin) x1 = margin;
    if  (y1 < margin) y1 = margin;
    if  (x2 > xsize - margin)    x2 = xsize - margin;
    if  (y2 > ysize - margin)    y2 = ysize - margin;
    bu.area.a.x = x1;
    bu.area.a.y = y1;
    bu.area.b.x = x2;
    bu.area.b.y = y2;
    bu.border_colour = bord;
    bu.body_colour = body;
    strcpy  (bu.txt1, txt1);
    strcpy  (bu.txt2, txt2);
    bu.in_use = true;
    bu.pressed = false;
    draw_button(bu);
}

/*bool    ifpressed   (int key)
{
    return  button[key].pressed;
}
*/
bool    is_button_pressed   (struct point & pt, struct button_specs & bu)
{
    if  (bu.in_use)  {
        if  (   bu.area.a.x < pt.x 
                && bu.area.b.x > pt.x
                && bu.area.a.y < pt.y 
                && bu.area.b.y > pt.y)
            return  true;
    }
    return  false;
}

int get_button_press    (struct point & pt)
{
    for (int j = 0; j < NUMOF_BUTTONS; j++)
        if  (button[j].in_use && is_button_pressed   (pt, button[j]))
            return  j;
    return  -1;
}

void    setup_buttons   ()
{
    setup_button    (button[SPEEDO_BUTTON],
                    SPEEDO_X - SPEEDO_SIZE, SPEEDO_Y - SPEEDO_SIZE,
                    SPEEDO_SIZE * 2, SPEEDO_SIZE * 2, SPEEDO_BODY_COLOUR,   LCD_COLOR_RED,   " X", "")  ;
    setup_button    (button[VMETER_BUTTON],
                    VOLTMETER_X - V_A_SIZE, VOLTMETER_Y - V_A_SIZE, V_A_SIZE * 2, V_A_SIZE * 2, VMETER_BODY_COLOUR,   LCD_COLOR_RED,   " Y", "")  ;
    setup_button    (button[AMETER_BUTTON],
                    AMMETER_X - V_A_SIZE, AMMETER_Y - V_A_SIZE, V_A_SIZE * 2, V_A_SIZE * 2, AMETER_BODY_COLOUR,   LCD_COLOR_RED,   " Z", "")  ;
    setup_button    (button[SLIDER_BUTTON],   SLIDERX, SLIDERY, SLIDERW, SLIDERH, LCD_COLOR_BLUE,   LCD_COLOR_MAGENTA,   "", "")  ;
}

void    screen_touch_handler::DrawSlider    ()  {
    uint32_t
        colr,
        oldbgcolr   = lcd.GetBackColor   (),
        oldtxtcolr  = lcd.GetTextColor   ();
    char    txt[4];
    txt[1] = 0;
    if  (position > MAX_POS)
        position = MAX_POS;
    if  (position < MIN_POS)
        position = MIN_POS;
    if  (position != oldpos)    {
        //  Draw slider background colour rectangle overwriting previous circles
        //  Redraw black vertical
        //  Draw new circles
        //  Write text char
        lcd.SetTextColor(LCD_COLOR_MAGENTA);
        lcd.FillRect    (SLIDERX + 1, oldpos - BUTTON_RAD, SLIDERW - 2, SLIDERW);
        lcd.SetTextColor(LCD_COLOR_BLACK);
        lcd.FillRect    (SLIDERX + (SLIDERW / 2) - 3, 6, 7, SLIDERH - 8);
        oldpos = position;
        lcd.SetTextColor(LCD_COLOR_WHITE);
        lcd.DrawCircle  (CIRC_CTR, position, BUTTON_RAD);  //  seel also FillCircle
        lcd.DrawCircle  (CIRC_CTR, position, BUTTON_RAD - 1);
        switch  (next_state)  {
            case    RUN_DOWN:
            case    RUN:
                txt[0] = 'R';
                colr = LCD_COLOR_GREEN;
                break;
            case    INTO_NEUTRAL_DRIFT:
            case    NEUTRAL_DRIFT:
            case    INTO_RUN:
                txt[0] = 'N';
                colr = LCD_COLOR_BLUE;
                break;
            case    REGEN_BRAKE:
            case    INTO_REGEN_BRAKE:
                txt[0] = 'B';
                colr = LCD_COLOR_ORANGE;
                break;
            default:
                txt[0] = 'X';
                colr = LCD_COLOR_CYAN;
//                pc.printf   ("State %d\r\n", next_state);
        }   //  End of switch
        lcd.SetTextColor(colr);
        lcd.FillCircle  (CIRC_CTR, position, BUTTON_RAD - 2);
        lcd.SetBackColor  (colr);
        lcd.SetTextColor(LCD_COLOR_YELLOW);
        displaytext(SLIDERX + 17, position - 10, 4, txt);   //  largest font
        lcd.SetBackColor  (LCD_COLOR_BLACK);
    }           //  End of else
    lcd.SetTextColor (oldtxtcolr);
    lcd.SetBackColor (oldbgcolr);
}