Electric Locomotive control system. Touch screen driver control, includes regenerative braking, drives 4 brushless motors, displays speed MPH, system volts and power

Dependencies:   BSP_DISCO_F746NG FastPWM LCD_DISCO_F746NG SD_DISCO_F746NG TS_DISCO_F746NG mbed

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers graphics.cpp Source File

graphics.cpp

00001 #include "mbed.h"
00002 #include "TS_DISCO_F746NG.h"
00003 #include "LCD_DISCO_F746NG.h"
00004 #include "Electric_Loco.h"
00005 
00006 #define VOLTMETER_X 68      //  Voltmeter screen position
00007 #define VOLTMETER_Y 68
00008 #define AMMETER_X   68      //  Ammeter screen position - Now replaced by Power meter
00009 #define AMMETER_Y   202
00010 #define SPEEDO_X    274     //  Speedometer screen position
00011 #define SPEEDO_Y    135
00012 #define V_A_SIZE    54      //  Size of voltmeter and ammeter
00013 #define SPEEDO_SIZE 112
00014 
00015 #define SPEEDO_BODY_COLOUR  LCD_COLOR_BLACK
00016 #define SPEEDO_DIAL_COLOUR  LCD_COLOR_WHITE
00017 #define SPEEDO_TEXT_COLOUR  LCD_COLOR_BLUE
00018 
00019 #define VMETER_BODY_COLOUR  LCD_COLOR_BLACK
00020 #define VMETER_DIAL_COLOUR  LCD_COLOR_WHITE
00021 #define VMETER_TEXT_COLOUR  LCD_COLOR_BLUE
00022 
00023 #define AMETER_BODY_COLOUR  LCD_COLOR_BLACK
00024 #define AMETER_DIAL_COLOUR  LCD_COLOR_WHITE
00025 #define AMETER_TEXT_COLOUR  LCD_COLOR_BLUE
00026 
00027 extern  LCD_DISCO_F746NG    lcd;
00028 extern  TS_DISCO_F746NG     touch_screen;
00029 extern  Serial pc;
00030 
00031 static const int    char_widths[]   = {5, 7, 11, 14, 17, 17}    ,
00032                     meter_radius_min = 30, meter_radius_max = 120;
00033 
00034 
00035 //  Uses our own generated sine and cosines from lookup table.  For some unexplained reason, using inbuilt sin and cos fns cause display flicker !
00036 extern double  jcos  (double angle);    //  Used in DrawNeedle, plain sin and cos functions cause display flicker !!
00037 extern double  jsin  (double angle);
00038 
00039 /*void    costabgen  (int points)  {
00040     double  angle = 0.0;
00041     while   (angle < 2.1 * PI)  {
00042         pc.printf   ("Angle %f, my cos %+f, c cos %+f\r\n", angle, jcos(angle), cos(angle));
00043 //        pc.printf   ("Angle %f, my sin %+f, c sin %+f\r\n", angle, jsin(angle), sin(angle));
00044         angle += PI / 24;
00045     }
00046 //    double  angle;
00047 *//*    int step, perline = 0;
00048     double  interval = PI / 2.0 / (double)points;
00049     pc.printf   ("//At costabgen with %d points\r\n", points);
00050     pc.printf   ("static const double costab[] = {\r\n");
00051     for (step = 0; step <= points; step++)  {
00052         angle   = interval * (double)step;
00053 //        pc.printf   ("cos %+.3f = %+.3f\r\n", angle, cos(angle));
00054         if  (++perline == 8)  {
00055             pc.printf   ("%+.6f,\r\n", cos(angle));
00056             perline = 0;
00057         }
00058         else
00059             pc.printf   ("%+.6f, ", cos(angle));
00060         wait    (0.025);
00061     }
00062     pc.printf   ("0.0\t}\t;\r\n//End of costab\r\n");
00063 */
00064 //}
00065 
00066 /**
00067   * @brief  Fills a triangle (between 3 points).
00068   * @param  x1: Point 1 X position
00069   * @param  y1: Point 1 Y position
00070   * @param  x2: Point 2 X position
00071   * @param  y2: Point 2 Y position
00072   * @param  x3: Point 3 X position
00073   * @param  y3: Point 3 Y position
00074   * @retval None
00075   */
00076 static void FillTriangle(uint16_t x1, uint16_t x2, uint16_t x3, uint16_t y1, uint16_t y2, uint16_t y3)
00077 {
00078     int16_t deltax = 0, deltay = 0, x = 0, y = 0, xinc1 = 0, xinc2 = 0,
00079             yinc1 = 0, yinc2 = 0, den = 0, num = 0, num_add = 0, num_pixels = 0,
00080             curpixel = 0;
00081 
00082     deltax = abs(x2 - x1);        /* The difference between the x's */
00083     deltay = abs(y2 - y1);        /* The difference between the y's */
00084     x = x1;                       /* Start x off at the first pixel */
00085     y = y1;                       /* Start y off at the first pixel */
00086 
00087     if (x2 >= x1) {               /* The x-values are increasing */
00088         xinc1 = 1;
00089         xinc2 = 1;
00090     } else {                      /* The x-values are decreasing */
00091         xinc1 = -1;
00092         xinc2 = -1;
00093     }
00094 
00095     if (y2 >= y1) {               /* The y-values are increasing */
00096         yinc1 = 1;
00097         yinc2 = 1;
00098     } else {                      /* The y-values are decreasing */
00099         yinc1 = -1;
00100         yinc2 = -1;
00101     }
00102 
00103     if (deltax >= deltay) {       /* There is at least one x-value for every y-value */
00104         xinc1 = 0;                  /* Don't change the x when numerator >= denominator */
00105         yinc2 = 0;                  /* Don't change the y for every iteration */
00106         den = deltax;
00107         num = deltax / 2;
00108         num_add = deltay;
00109         num_pixels = deltax;         /* There are more x-values than y-values */
00110     } else {                      /* There is at least one y-value for every x-value */
00111         xinc2 = 0;                  /* Don't change the x for every iteration */
00112         yinc1 = 0;                  /* Don't change the y when numerator >= denominator */
00113         den = deltay;
00114         num = deltay / 2;
00115         num_add = deltax;
00116         num_pixels = deltay;         /* There are more y-values than x-values */
00117     }
00118 
00119     for (curpixel = 0; curpixel <= num_pixels; curpixel++) {
00120         lcd.DrawLine(x, y, x3, y3);
00121 
00122         num += num_add;              /* Increase the numerator by the top of the fraction */
00123         if (num >= den) {           /* Check if numerator >= denominator */
00124             num -= den;               /* Calculate the new numerator value */
00125             x += xinc1;               /* Change the x as appropriate */
00126             y += yinc1;               /* Change the y as appropriate */
00127         }
00128         x += xinc2;                 /* Change the x as appropriate */
00129         y += yinc2;                 /* Change the y as appropriate */
00130     }
00131 }
00132 
00133 double  anglefix    (double a)  {       //  Ensures 0.0 <= angle <= + two PI
00134     while   (a > PI) a   -= 2.0 * PI;
00135     while   (a < 0.0) a   += 2.0 * PI;
00136     return  a;
00137 }
00138 
00139 class    moving_coil_meter
00140 {
00141     int     meter_radius, cent_x, cent_y, needle_len, scale_ticks,
00142             disc_colour,    needle_colour,  scale_colour,   text_colour, body_colour, dec_places;
00143     double  start_angle, end_angle, old_angle, value_min, value_max, rad_per_value, swept_angle, value_range;
00144     double  Value;  //  This is the one that determines pointer angle
00145 
00146     void    DrawNeedle          (double alpha, int colour)  ;
00147     void    DrawScaleGraduations(int colour)  ;
00148     double  get_pointer_angle   (double value)  ;
00149     int     get_font            ()  ;
00150 
00151 public:
00152 
00153     moving_coil_meter   ()  {   //  constructor
00154         meter_radius = 100;
00155         value_min = -1.0;
00156         value_max = 1.0;
00157         cent_x = cent_y = 150;
00158         disc_colour     = LCD_COLOR_BLACK;
00159         needle_colour   = LCD_COLOR_WHITE;
00160         scale_colour    = LCD_COLOR_MAGENTA;
00161         text_colour     = LCD_COLOR_RED;
00162         body_colour     = LCD_COLOR_CYAN;
00163         old_angle       = 0.0;
00164     }
00165 
00166     bool    setup   (int cx, int cy, int size, double lo, double hi, double start_ang, double end_ang, int scaleticks, char * units, int decimal_places)  ;
00167     void    set_colours   (int bod_colour, int bgcol, int needlecol, int textcolour, int scalecol)  ;
00168     void    set_value   (double v)  ;
00169 }   Voltmeter,  Powermeter,    Speedo;     //  3 instances of moving coil meter graphic
00170 
00171 void    moving_coil_meter::set_colours   (int bod_col, int bgcol, int needlecol, int textcol, int scalecol)  {
00172     body_colour = bod_col;
00173     disc_colour = bgcol;
00174     needle_colour   = needlecol;
00175     text_colour = textcol;
00176     scale_colour    = scalecol;
00177 }
00178 
00179 void    moving_coil_meter::DrawNeedle  (double alpha, int colour)
00180 {
00181     point  pixpts[4];
00182     int save_colour, ssa, sca;
00183     alpha   = anglefix  (alpha);
00184     double  shortln = (needle_len / 18.7),
00185             sina    = jsin(alpha),
00186             cosa    = jcos(alpha);
00187 
00188     save_colour = lcd.GetTextColor  ();
00189     ssa = (int)(shortln * sina);
00190     sca = (int)(shortln * cosa);
00191     old_angle = alpha;
00192     pixpts[0].x = cent_x - ssa;//(int)(shortln * sin(alpha));
00193     pixpts[0].y = cent_y - sca;//(int)(shortln * cos(alpha));
00194     pixpts[1].x = cent_x + (int)(needle_len * cosa);
00195     pixpts[1].y = cent_y - (int)(needle_len * sina);  //  - as increasing y is downwards
00196     pixpts[2].x = cent_x + ssa;//(int)(shortln * sin(alpha));
00197     pixpts[2].y = cent_y + sca;//(int)(shortln * cos(alpha));
00198     lcd.SetTextColor    (colour);
00199     lcd.FillCircle      (cent_x, cent_y, (int)(needle_len / 15.0));
00200     FillTriangle    (pixpts[0].x, pixpts[1].x, pixpts[2].x, pixpts[0].y, pixpts[1].y, pixpts[2].y);
00201     lcd.SetTextColor    (save_colour);
00202 }
00203 
00204 void    moving_coil_meter::DrawScaleGraduations (int colour)
00205 {
00206     int save_colour = lcd.GetTextColor  ();
00207     int i, radius_inner = (int) meter_radius - 2, radius_outer = (int) (meter_radius * 0.9);
00208     double  ang, cosang, sinang, angle_step;
00209     lcd.SetTextColor    (colour);
00210     ang = start_angle;
00211     angle_step  = (start_angle - end_angle) / scale_ticks;
00212     for (i = 0; i <= scale_ticks; i++)   {   //
00213         cosang  = cos(ang);
00214         sinang  = sin(ang);
00215         lcd.DrawLine    (cent_x + radius_outer * cosang, cent_y - radius_outer * sinang, cent_x + radius_inner * cosang, cent_y - radius_inner * sinang);
00216         ang -= angle_step;
00217     }
00218     lcd.SetTextColor    (save_colour);
00219 }
00220 
00221 void    displaytext    (int x, int y, const int font, char * txt)   ;
00222 
00223 bool    moving_coil_meter::setup   (int cx, int cy, int size, double lo, double hi, double start_ang, double end_ang, int scaleticks, char * units, int decimal_places)
00224 {
00225     bool    retval = true;
00226     int font, charwid, x_offset;
00227     if  (size < meter_radius_min || size > meter_radius_max)
00228         return  false;
00229     meter_radius = size;
00230     if  (meter_radius > cx || meter_radius > cy)
00231         return  false;
00232     int corner_rad          = meter_radius / 6,
00233         screw_hole_offset   = meter_radius * 92 / 100,
00234         screw_rad           = meter_radius / 13;
00235     cent_x = cx;
00236     cent_y = cy;
00237 
00238     start_angle = start_ang;
00239     end_angle = end_ang;
00240     value_min = lo;
00241     value_max = hi;
00242     scale_ticks = scaleticks;
00243     swept_angle = abs(start_angle - end_angle);
00244     value_range = (value_max - value_min);
00245     rad_per_value = swept_angle / value_range;
00246     dec_places  = decimal_places;
00247 
00248     needle_len = (int)(0.87 * (double)meter_radius);
00249     int oldcolour1 = lcd.GetTextColor   ();
00250     int oldcolour2 = lcd.GetBackColor   ();
00251     lcd.SetTextColor    (body_colour);
00252     //  Draw meter body as solid square with rounded corners, complete with mounting screw holes !
00253     lcd.FillRect    (cent_x - meter_radius, cent_y - meter_radius - corner_rad, meter_radius * 2, corner_rad);
00254     lcd.FillRect    (cent_x - meter_radius, cent_y + meter_radius, meter_radius * 2, corner_rad + 1);
00255     lcd.FillRect    (cent_x - meter_radius - corner_rad, cent_y - meter_radius, 1 +(meter_radius + corner_rad) * 2, meter_radius * 2);
00256     lcd.FillCircle  (cent_x - meter_radius, cent_y - meter_radius, corner_rad);  //  meter box has rounded corners
00257     lcd.FillCircle  (cent_x - meter_radius, cent_y + meter_radius, corner_rad);
00258     lcd.FillCircle  (cent_x + meter_radius, cent_y - meter_radius, corner_rad);
00259     lcd.FillCircle  (cent_x + meter_radius, cent_y + meter_radius, corner_rad);
00260     lcd.SetTextColor    (LCD_COLOR_DARKGRAY);
00261     lcd.FillCircle  (cent_x - screw_hole_offset, cent_y - screw_hole_offset, screw_rad);  //  panel mounting screw holes near corners
00262     lcd.FillCircle  (cent_x - screw_hole_offset, cent_y + screw_hole_offset, screw_rad);
00263     lcd.FillCircle  (cent_x + screw_hole_offset, cent_y - screw_hole_offset, screw_rad);
00264     lcd.FillCircle  (cent_x + screw_hole_offset, cent_y + screw_hole_offset, screw_rad);
00265     lcd.SetTextColor    (disc_colour);
00266     lcd.FillCircle      (cent_x, cent_y, meter_radius);
00267     DrawScaleGraduations (scale_colour);   //drew the green trace around active needle-sweep angle
00268 
00269     font = get_font ();
00270     charwid = char_widths[font];
00271     x_offset = charwid * strlen(units) / 2;
00272     lcd.SetTextColor    (text_colour);
00273     lcd.SetBackColor    (disc_colour);
00274 //    displaytext (cent_x - x_offset, cent_y + (meter_radius * 7) / 19, font, units);
00275     displaytext (cent_x - x_offset, cent_y + (meter_radius * 6) / 19, font, units);
00276     lcd.SetBackColor    (oldcolour2);
00277     lcd.SetTextColor    (oldcolour1);
00278     return  retval;
00279 }
00280 
00281 int     moving_coil_meter::get_font ()
00282 {
00283     int font = meter_radius - meter_radius_min;
00284     font /= 17;
00285     if  (font > 4)
00286         font = 4;
00287     if  (font < 2)
00288         font = 2;
00289     return  font;
00290 }
00291 
00292 double  moving_coil_meter::get_pointer_angle    (double v)
00293 {
00294     double   vabvmin, retval;
00295     if   (v < value_min) v = value_min;
00296     if   (v > value_max) v = value_max;
00297     Value = v;   //  clipped copy of supplied value
00298     vabvmin = v - value_min;
00299     retval   = start_angle - (vabvmin * rad_per_value);
00300     return   anglefix   (retval);
00301 }
00302 
00303 void    moving_coil_meter::set_value   (double meter_read_value)
00304 {
00305     char    txt[32];
00306     int x_offset, font, charwid, lenchk;//,
00307     DrawNeedle  (old_angle, disc_colour);                   //  un-draw needle
00308     DrawNeedle  (get_pointer_angle   (meter_read_value), needle_colour)  ; //  re-draw needle
00309     if  (dec_places == ONE_DP)
00310         sprintf (txt, " %+.1f \0", meter_read_value);
00311     else
00312         sprintf (txt, " %+.0f \0", meter_read_value);
00313     lenchk = strlen(txt);
00314     font = get_font();
00315     charwid = char_widths[font];
00316     x_offset = charwid * lenchk / 2;
00317     lcd.SetTextColor    (text_colour);
00318     lcd.SetBackColor    (disc_colour);
00319     if  (lenchk > 0 && lenchk < 9)
00320         displaytext (cent_x - x_offset, cent_y + (meter_radius * 11) / 19, font, txt);
00321 }
00322 //bool    moving_coil_meter::setup   (int cx, int cy, int size, double lo, double hi, double start_ang, double end_ang,
00323 //                                    int scale_ticks, char * units)
00324 void    vm_set  ()   //x   y  size minv  maxv  min angle   max angle,
00325 {
00326     Speedo.set_colours  (SPEEDO_BODY_COLOUR, SPEEDO_DIAL_COLOUR, LCD_COLOR_RED, SPEEDO_TEXT_COLOUR, LCD_COLOR_BLACK);
00327     Speedo.setup    (SPEEDO_X, SPEEDO_Y, SPEEDO_SIZE, 0.0, 12.0, 1.25 * PI, -0.25 * PI , 12, "MPH", ONE_DP);
00328     Voltmeter.set_colours  (LCD_COLOR_BLACK, LCD_COLOR_WHITE, LCD_COLOR_RED, LCD_COLOR_BLUE, LCD_COLOR_MAGENTA);
00329     Voltmeter.setup (VOLTMETER_X, VOLTMETER_Y, V_A_SIZE, 22.0, 59.0, 1.25 * PI, -0.25 * PI , 30, "V", ONE_DP);
00330     Powermeter.set_colours  (LCD_COLOR_BLACK, LCD_COLOR_WHITE, LCD_COLOR_RED, LCD_COLOR_BLUE, LCD_COLOR_BLUE);
00331     Powermeter.setup   (AMMETER_X, AMMETER_Y, V_A_SIZE, -1400.0, 1400.0, 1.25 * PI, -0.25 * PI , 14, "Watt", NO_DPS);
00332 }
00333 
00334 //void    update_meters  (double speed, double current, double voltage)
00335 void    update_meters  (double speed, double power, double voltage)
00336 {
00337 //    Powermeter.set_value(voltage * current);
00338     Powermeter.set_value(power);
00339     Voltmeter.set_value (voltage);
00340     Speedo.set_value    (speed);
00341 }
00342 
00343 
00344 
00345 struct  rect    {   struct point a, b; }   ;
00346 
00347 struct  butt_on  {
00348     struct  rect    area;
00349     int border_colour,  body_colour;
00350     bool    in_use, pressed;//, released;
00351     char txt1[12];
00352     char txt2[12];
00353 }   ;
00354 
00355 struct  butt_on   button[NUMOF_BUTTONS];
00356 
00357 int get_button_press    (struct point & pt) ;
00358 int get_but_p   (int x, int y)
00359 {
00360     struct  point   p;
00361     p.x = x;
00362     p.y = y;
00363     return  get_button_press    (p);
00364 }
00365 
00366 
00367 void    read_keypresses    (struct ky_bd & a)
00368 {
00369     int x;
00370     a.count = 0;
00371     a.sli   = false;
00372     for (x = 0; x < MAX_TOUCHES; x++)
00373         a.ky[x].keynum = -1;
00374     int touches, but;
00375     TS_StateTypeDef TS_State;
00376     touch_screen.GetState(&TS_State);
00377     touches = TS_State.touchDetected;
00378     for (int h = 0; h < touches; h++)   {
00379         but = get_but_p  (TS_State.touchX[h], TS_State.touchY[h]);
00380         if  (but > - 1) {
00381             a.ky[a.count].keynum = but;
00382             a.ky[a.count].x     = TS_State.touchX[h];
00383             a.ky[a.count].y     = TS_State.touchY[h];
00384             if  (but == SLIDER) {
00385                 a.sli   = true;
00386                 a.slider_y  = a.ky[a.count].y;
00387             }
00388             a.count++;
00389         }
00390     }
00391 }
00392 
00393 
00394 void    displaytext    (int x, int y, char * txt)
00395 {
00396     lcd.DisplayStringAt(x, y, (uint8_t *)txt, LEFT_MODE);
00397 }
00398 
00399 void    displaytext    (int x, int y, const int font, char * txt)
00400 {
00401     sFONT * const fp[] = {&Font8, &Font12, &Font16, &Font20, &Font24};
00402     lcd.SetFont(fp[font]);
00403     displaytext (x, y, txt);
00404 }
00405 
00406 void    displaytext    (int x, int y, const int font, uint32_t BCol, uint32_t TCol, char * txt)
00407 {
00408     uint32_t otc, obc;
00409     otc = lcd.GetTextColor();
00410     obc = lcd.GetBackColor();
00411     lcd.SetTextColor(TCol);
00412     lcd.SetBackColor(BCol);
00413     displaytext (x, y, font, txt);
00414     lcd.SetTextColor(otc);
00415     lcd.SetBackColor(obc);
00416 }
00417 
00418 void    draw_button (struct butt_on & bu)
00419 {
00420     int oldbgcolour;
00421     lcd.SetTextColor    (bu.body_colour);
00422     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);
00423     oldbgcolour = lcd.GetBackColor();
00424     lcd.SetBackColor(bu.body_colour);
00425     lcd.SetTextColor(LCD_COLOR_BLACK);
00426     if  (strlen(bu.txt2) == 0)   {
00427         displaytext     (bu.area.a.x + 4, bu.area.a.y + 14, 4, bu.txt1); //  largest font 4
00428     } else    {
00429         displaytext     (bu.area.a.x + 4, bu.area.a.y + 4, 3, bu.txt1); //  not so large font 3
00430         displaytext     (bu.area.a.x + 4, bu.area.a.y + 26, bu.txt2);
00431     }
00432     lcd.SetBackColor(LCD_COLOR_BLACK);
00433     lcd.SetTextColor(bu.border_colour);
00434     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);
00435     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);
00436     lcd.SetBackColor(oldbgcolour);
00437 }
00438 
00439 void    draw_button_hilight     (int but, int colour)
00440 {
00441     if  (but < 0 || but > NUMOF_BUTTONS)    {
00442         pc.printf   ("Button out of range in draw_button_hilight %d\r\n", but)  ;
00443     } else    {
00444         struct   butt_on * bu = &button[but];
00445         int oldbgcolour = lcd.GetBackColor();//, minx, miny, maxx, maxy;
00446         lcd.SetTextColor(colour);
00447         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);
00448         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);
00449         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);
00450         lcd.SetBackColor(oldbgcolour);
00451     }
00452 }
00453 
00454 void    draw_button (struct butt_on & bu, int body_colour)
00455 {
00456     bu.body_colour = body_colour;
00457     draw_button (bu);
00458 }
00459 
00460 void    setup_button    (struct butt_on & bu, int x1, int y1, int dx, int dy, int bord, int body, char * txt1, char * txt2)
00461 {
00462     static const int margin = 3;
00463     int xsize = lcd.GetXSize();
00464     int ysize = lcd.GetXSize();
00465     int x2 = x1 + dx, y2 = y1 + dy;
00466     if  (x1 < margin) x1 = margin;
00467     if  (y1 < margin) y1 = margin;
00468     if  (x2 > xsize - margin)    x2 = xsize - margin;
00469     if  (y2 > ysize - margin)    y2 = ysize - margin;
00470     bu.area.a.x = x1;
00471     bu.area.a.y = y1;
00472     bu.area.b.x = x2;
00473     bu.area.b.y = y2;
00474     bu.border_colour = bord;
00475     bu.body_colour = body;
00476     strcpy  (bu.txt1, txt1);
00477     strcpy  (bu.txt2, txt2);
00478     bu.in_use = true;
00479     bu.pressed = false;
00480     draw_button(bu);
00481 }
00482 
00483 bool    ifpressed   (int key)
00484 {
00485     return  button[key].pressed;
00486 }
00487 
00488 bool    is_button_pressed   (struct point & pt, struct butt_on & bu)
00489 {
00490     if  (bu.in_use)  {
00491         if  (bu.area.a.x < pt.x && bu.area.b.x > pt.x
00492                 && bu.area.a.y < pt.y && bu.area.b.y > pt.y)
00493             return  true;
00494     }
00495     return  false;
00496 }
00497 
00498 bool    keyrelease  (int key)
00499 {
00500     bool    rv = false;
00501     if  (button[key].pressed)   {
00502         rv = true;
00503         button[key].pressed = false;
00504     }
00505     return  rv;
00506 }
00507 void    setpressed  (int key, bool torf)
00508 {
00509     button[key].pressed = torf;
00510 }
00511 void    setinuse    (int key, bool torf)
00512 {
00513     button[key].in_use = torf;
00514 }
00515 
00516 
00517 int get_button_press    (struct point & pt)
00518 {
00519     for (int j = 0; j < NUMOF_BUTTONS; j++)
00520         if  (button[j].in_use && is_button_pressed   (pt, button[j]))
00521             return  j;
00522     return  -1;
00523 }
00524 
00525 void    setup_buttons   ()
00526 {
00527     setup_button    (button[SPEEDO_BUT],
00528                     SPEEDO_X - SPEEDO_SIZE, SPEEDO_Y - SPEEDO_SIZE,
00529                     SPEEDO_SIZE * 2, SPEEDO_SIZE * 2, SPEEDO_BODY_COLOUR,   LCD_COLOR_RED,   " X", "")  ;
00530     setup_button    (button[VMETER_BUT],
00531                     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", "")  ;
00532     setup_button    (button[AMETER_BUT],
00533                     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", "")  ;
00534     setup_button    (button[SLIDER],   SLIDERX, SLIDERY, SLIDERW, SLIDERH, LCD_COLOR_BLUE,   LCD_COLOR_MAGENTA,   "", "")  ;
00535 }
00536 
00537 
00538 void SliderGraphic (struct slide & q)   {
00539     int
00540     colr,
00541     oldbgcolr   = lcd.GetBackColor   (),
00542     oldtxtcolr  = lcd.GetTextColor   ();
00543     char    txt[4];
00544     txt[1] = 0;
00545     if  (q.position > MAX_POS)
00546         q.position = MAX_POS;
00547     if  (q.position < MIN_POS)
00548         q.position = MIN_POS;
00549     if  (q.position == NEUTRAL_VAL)
00550         q.state = NEUTRAL_DRIFT;
00551     if  (q.position > NEUTRAL_VAL)
00552         q.state = REGEN_BRAKE;
00553     if  (q.position < NEUTRAL_VAL)
00554         if  (q.state == REGEN_BRAKE)    {   //  Ensure transition from BRAKE to RUN passes through NEUTRAL
00555             q.position = NEUTRAL_VAL;
00556             q.state = NEUTRAL_DRIFT;
00557         }
00558         else
00559             q.state = RUN;
00560     if  (q.position == MAX_POS) {
00561         if  (q.loco_speed < LOCO_HANDBRAKE_ESCAPE_SPEED)
00562             q.state = PARK;
00563         else    {
00564             q.state = REGEN_BRAKE;
00565             q.position--;
00566         }
00567     }
00568     if  (q.position != q.oldpos)    {
00569         //  Draw slider background colour rectangle overwriting previous circles
00570         //  Redraw black vertical
00571         //  Draw new circles
00572         //  Write text char
00573         lcd.SetTextColor(LCD_COLOR_MAGENTA);
00574         lcd.FillRect    (SLIDERX + 1, q.oldpos - BUTTON_RAD, SLIDERW - 2, SLIDERW);
00575         lcd.SetTextColor(LCD_COLOR_BLACK);
00576         lcd.FillRect    (SLIDERX + (SLIDERW / 2) - 3, 6, 7, SLIDERH - 8);
00577         q.oldpos = q.position;
00578         lcd.SetTextColor(LCD_COLOR_WHITE);
00579         lcd.DrawCircle  (CIRC_CTR, q.position, BUTTON_RAD);  //  seel also FillCircle
00580         lcd.DrawCircle  (CIRC_CTR, q.position, BUTTON_RAD - 1);
00581         switch  (q.state)  {
00582             case    RUN:
00583                 txt[0] = 'R';
00584                 colr = LCD_COLOR_GREEN;
00585                 break;
00586             case    NEUTRAL_DRIFT:
00587                 txt[0] = 'N';
00588                 colr = LCD_COLOR_BLUE;
00589                 break;
00590             case    REGEN_BRAKE:
00591                 txt[0] = 'B';
00592                 colr = LCD_COLOR_ORANGE;
00593                 break;
00594             case    PARK:
00595                 txt[0] = 'P';
00596                 colr = LCD_COLOR_RED;
00597                 break;
00598             default:
00599                 txt[0] = 'X';
00600                 colr = LCD_COLOR_CYAN;
00601         }   //  End of switch
00602         lcd.SetTextColor(colr);
00603         lcd.FillCircle  (CIRC_CTR, q.position, BUTTON_RAD - 2);
00604         lcd.SetBackColor  (colr);
00605         lcd.SetTextColor(LCD_COLOR_YELLOW);
00606         displaytext(SLIDERX + 17, q.position - 10, 4, txt);   //  largest font
00607         lcd.SetBackColor  (LCD_COLOR_BLACK);
00608     }           //  End of else
00609     lcd.SetTextColor (oldtxtcolr);
00610     lcd.SetBackColor (oldbgcolr);
00611 //    pc.printf   ("SliderG %d, %d, %d\r\n", q.position, q.oldpos, q.state);
00612 }
00613 
00614 
00615 
00616