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
Diff: graphics.cpp
- Revision:
- 0:23cc72b18e74
- Child:
- 1:8ef34deb5177
diff -r 000000000000 -r 23cc72b18e74 graphics.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graphics.cpp Sun Nov 12 06:26:29 2017 +0000 @@ -0,0 +1,614 @@ +#include "mbed.h" +#include "TS_DISCO_F746NG.h" +#include "LCD_DISCO_F746NG.h" +#include "dro.h" + +#define VOLTMETER_X 68 // Voltmeter screen position +#define VOLTMETER_Y 68 +#define AMMETER_X 68 // Ammeter screen position - Now replaced by Power meter +#define AMMETER_Y 202 +#define SPEEDO_X 274 // Speedometer screen position +#define SPEEDO_Y 135 +#define V_A_SIZE 54 // Size of voltmeter and ammeter +#define SPEEDO_SIZE 112 + +#define SPEEDO_BODY_COLOUR LCD_COLOR_BLACK +#define SPEEDO_DIAL_COLOUR LCD_COLOR_WHITE +#define SPEEDO_TEXT_COLOUR LCD_COLOR_BLUE + +#define VMETER_BODY_COLOUR LCD_COLOR_BLACK +#define VMETER_DIAL_COLOUR LCD_COLOR_WHITE +#define VMETER_TEXT_COLOUR LCD_COLOR_BLUE + +#define AMETER_BODY_COLOUR LCD_COLOR_BLACK +#define AMETER_DIAL_COLOUR LCD_COLOR_WHITE +#define AMETER_TEXT_COLOUR LCD_COLOR_BLUE + +extern LCD_DISCO_F746NG lcd; +extern TS_DISCO_F746NG touch_screen; +extern Serial pc; + +static const int char_widths[] = {5, 7, 11, 14, 17, 17} , + meter_radius_min = 30, meter_radius_max = 120; + + +// Uses our own generated sine and cosines from lookup table. For some unexplained reason, using inbuilt sin and cos fns cause display flicker ! +extern double jcos (double angle); // Used in DrawNeedle, plain sin and cos functions cause display flicker !! +extern double jsin (double angle); + +/*void costabgen (int points) { + double angle = 0.0; + while (angle < 2.1 * PI) { + pc.printf ("Angle %f, my cos %+f, c cos %+f\r\n", angle, jcos(angle), cos(angle)); +// pc.printf ("Angle %f, my sin %+f, c sin %+f\r\n", angle, jsin(angle), sin(angle)); + angle += PI / 24; + } +// double angle; +*//* int step, perline = 0; + double interval = PI / 2.0 / (double)points; + pc.printf ("//At costabgen with %d points\r\n", points); + pc.printf ("static const double costab[] = {\r\n"); + for (step = 0; step <= points; step++) { + angle = interval * (double)step; +// pc.printf ("cos %+.3f = %+.3f\r\n", angle, cos(angle)); + if (++perline == 8) { + pc.printf ("%+.6f,\r\n", cos(angle)); + perline = 0; + } + else + pc.printf ("%+.6f, ", cos(angle)); + wait (0.025); + } + pc.printf ("0.0\t}\t;\r\n//End of costab\r\n"); +*/ +//} + +/** + * @brief Fills a triangle (between 3 points). + * @param x1: Point 1 X position + * @param y1: Point 1 Y position + * @param x2: Point 2 X position + * @param y2: Point 2 Y position + * @param x3: Point 3 X position + * @param y3: Point 3 Y position + * @retval None + */ +static void FillTriangle(uint16_t x1, uint16_t x2, uint16_t x3, uint16_t y1, uint16_t y2, uint16_t y3) +{ + int16_t deltax = 0, deltay = 0, x = 0, y = 0, xinc1 = 0, xinc2 = 0, + yinc1 = 0, yinc2 = 0, den = 0, num = 0, num_add = 0, num_pixels = 0, + curpixel = 0; + + deltax = abs(x2 - x1); /* The difference between the x's */ + deltay = abs(y2 - y1); /* The difference between the y's */ + x = x1; /* Start x off at the first pixel */ + y = y1; /* Start y off at the first pixel */ + + if (x2 >= x1) { /* The x-values are increasing */ + xinc1 = 1; + xinc2 = 1; + } else { /* The x-values are decreasing */ + xinc1 = -1; + xinc2 = -1; + } + + if (y2 >= y1) { /* The y-values are increasing */ + yinc1 = 1; + yinc2 = 1; + } else { /* The y-values are decreasing */ + yinc1 = -1; + yinc2 = -1; + } + + if (deltax >= deltay) { /* There is at least one x-value for every y-value */ + xinc1 = 0; /* Don't change the x when numerator >= denominator */ + yinc2 = 0; /* Don't change the y for every iteration */ + den = deltax; + num = deltax / 2; + num_add = deltay; + num_pixels = deltax; /* There are more x-values than y-values */ + } else { /* There is at least one y-value for every x-value */ + xinc2 = 0; /* Don't change the x for every iteration */ + yinc1 = 0; /* Don't change the y when numerator >= denominator */ + den = deltay; + num = deltay / 2; + num_add = deltax; + num_pixels = deltay; /* There are more y-values than x-values */ + } + + for (curpixel = 0; curpixel <= num_pixels; curpixel++) { + lcd.DrawLine(x, y, x3, y3); + + num += num_add; /* Increase the numerator by the top of the fraction */ + if (num >= den) { /* Check if numerator >= denominator */ + num -= den; /* Calculate the new numerator value */ + x += xinc1; /* Change the x as appropriate */ + y += yinc1; /* Change the y as appropriate */ + } + x += xinc2; /* Change the x as appropriate */ + y += yinc2; /* Change the y as appropriate */ + } +} + +double anglefix (double a) { // Ensures 0.0 <= angle <= + two PI + while (a > PI) a -= 2.0 * PI; + while (a < 0.0) a += 2.0 * PI; + return a; +} + +class moving_coil_meter +{ + int meter_radius, cent_x, cent_y, needle_len, scale_ticks, + disc_colour, needle_colour, scale_colour, text_colour, body_colour, dec_places; + double start_angle, end_angle, old_angle, value_min, value_max, rad_per_value, swept_angle, value_range; + double Value; // This is the one that determines pointer angle + + void DrawNeedle (double alpha, int colour) ; + void DrawScaleGraduations(int colour) ; + double get_pointer_angle (double value) ; + int get_font () ; + +public: + + moving_coil_meter () { // constructor + meter_radius = 100; + value_min = -1.0; + value_max = 1.0; + cent_x = cent_y = 150; + disc_colour = LCD_COLOR_BLACK; + needle_colour = LCD_COLOR_WHITE; + scale_colour = LCD_COLOR_MAGENTA; + text_colour = LCD_COLOR_RED; + body_colour = LCD_COLOR_CYAN; + old_angle = 0.0; + } + + 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) ; + void set_colours (int bod_colour, int bgcol, int needlecol, int textcolour, int scalecol) ; + void set_value (double v) ; +} Voltmeter, Powermeter, Speedo; // 3 instances of moving coil meter graphic + +void moving_coil_meter::set_colours (int bod_col, int bgcol, int needlecol, int textcol, int scalecol) { + body_colour = bod_col; + disc_colour = bgcol; + needle_colour = needlecol; + text_colour = textcol; + scale_colour = scalecol; +} + +void moving_coil_meter::DrawNeedle (double alpha, int colour) +{ + point pixpts[4]; + int save_colour, ssa, sca; + alpha = anglefix (alpha); + double shortln = (needle_len / 18.7), + sina = jsin(alpha), + cosa = jcos(alpha); + + save_colour = lcd.GetTextColor (); + ssa = (int)(shortln * sina); + sca = (int)(shortln * cosa); + old_angle = alpha; + pixpts[0].x = cent_x - ssa;//(int)(shortln * sin(alpha)); + pixpts[0].y = cent_y - sca;//(int)(shortln * cos(alpha)); + pixpts[1].x = cent_x + (int)(needle_len * cosa); + pixpts[1].y = cent_y - (int)(needle_len * sina); // - as increasing y is downwards + pixpts[2].x = cent_x + ssa;//(int)(shortln * sin(alpha)); + pixpts[2].y = cent_y + sca;//(int)(shortln * cos(alpha)); + lcd.SetTextColor (colour); + lcd.FillCircle (cent_x, cent_y, (int)(needle_len / 15.0)); + FillTriangle (pixpts[0].x, pixpts[1].x, pixpts[2].x, pixpts[0].y, pixpts[1].y, pixpts[2].y); + lcd.SetTextColor (save_colour); +} + +void moving_coil_meter::DrawScaleGraduations (int colour) +{ + int save_colour = lcd.GetTextColor (); + int i, radius_inner = (int) meter_radius - 2, radius_outer = (int) (meter_radius * 0.9); + double ang, cosang, sinang, angle_step; + lcd.SetTextColor (colour); + ang = start_angle; + angle_step = (start_angle - end_angle) / scale_ticks; + for (i = 0; i <= scale_ticks; i++) { // + cosang = cos(ang); + sinang = sin(ang); + lcd.DrawLine (cent_x + radius_outer * cosang, cent_y - radius_outer * sinang, cent_x + radius_inner * cosang, cent_y - radius_inner * sinang); + ang -= angle_step; + } + lcd.SetTextColor (save_colour); +} + +void displaytext (int x, int y, const int font, char * txt) ; + +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) +{ + bool retval = true; + int font, charwid, x_offset; + if (size < meter_radius_min || size > meter_radius_max) + return false; + meter_radius = size; + if (meter_radius > cx || meter_radius > cy) + return false; + int corner_rad = meter_radius / 6, + screw_hole_offset = meter_radius * 92 / 100, + screw_rad = meter_radius / 13; + cent_x = cx; + cent_y = cy; + + start_angle = start_ang; + end_angle = end_ang; + value_min = lo; + value_max = hi; + scale_ticks = scaleticks; + swept_angle = abs(start_angle - end_angle); + value_range = (value_max - value_min); + rad_per_value = swept_angle / value_range; + dec_places = decimal_places; + + needle_len = (int)(0.87 * (double)meter_radius); + int oldcolour1 = lcd.GetTextColor (); + int oldcolour2 = lcd.GetBackColor (); + lcd.SetTextColor (body_colour); + // Draw meter body as solid square with rounded corners, complete with mounting screw holes ! + lcd.FillRect (cent_x - meter_radius, cent_y - meter_radius - corner_rad, meter_radius * 2, corner_rad); + lcd.FillRect (cent_x - meter_radius, cent_y + meter_radius, meter_radius * 2, corner_rad + 1); + lcd.FillRect (cent_x - meter_radius - corner_rad, cent_y - meter_radius, 1 +(meter_radius + corner_rad) * 2, meter_radius * 2); + lcd.FillCircle (cent_x - meter_radius, cent_y - meter_radius, corner_rad); // meter box has rounded corners + lcd.FillCircle (cent_x - meter_radius, cent_y + meter_radius, corner_rad); + lcd.FillCircle (cent_x + meter_radius, cent_y - meter_radius, corner_rad); + lcd.FillCircle (cent_x + meter_radius, cent_y + meter_radius, corner_rad); + lcd.SetTextColor (LCD_COLOR_DARKGRAY); + lcd.FillCircle (cent_x - screw_hole_offset, cent_y - screw_hole_offset, screw_rad); // panel mounting screw holes near corners + lcd.FillCircle (cent_x - screw_hole_offset, cent_y + screw_hole_offset, screw_rad); + lcd.FillCircle (cent_x + screw_hole_offset, cent_y - screw_hole_offset, screw_rad); + lcd.FillCircle (cent_x + screw_hole_offset, cent_y + screw_hole_offset, screw_rad); + lcd.SetTextColor (disc_colour); + lcd.FillCircle (cent_x, cent_y, meter_radius); + DrawScaleGraduations (scale_colour); //drew the green trace around active needle-sweep angle + + font = get_font (); + charwid = char_widths[font]; + x_offset = charwid * strlen(units) / 2; + lcd.SetTextColor (text_colour); + lcd.SetBackColor (disc_colour); +// displaytext (cent_x - x_offset, cent_y + (meter_radius * 7) / 19, font, units); + displaytext (cent_x - x_offset, cent_y + (meter_radius * 6) / 19, font, units); + lcd.SetBackColor (oldcolour2); + lcd.SetTextColor (oldcolour1); + return retval; +} + +int moving_coil_meter::get_font () +{ + int font = meter_radius - meter_radius_min; + font /= 17; + if (font > 4) + font = 4; + if (font < 2) + font = 2; + return font; +} + +double moving_coil_meter::get_pointer_angle (double v) +{ + double vabvmin, retval; + if (v < value_min) v = value_min; + if (v > value_max) v = value_max; + Value = v; // clipped copy of supplied value + vabvmin = v - value_min; + retval = start_angle - (vabvmin * rad_per_value); + return anglefix (retval); +} + +void moving_coil_meter::set_value (double meter_read_value) +{ + char txt[32]; + int x_offset, font, charwid, lenchk;//, + DrawNeedle (old_angle, disc_colour); // un-draw needle + DrawNeedle (get_pointer_angle (meter_read_value), needle_colour) ; // re-draw needle + if (dec_places == ONE_DP) + sprintf (txt, " %+.1f \0", meter_read_value); + else + sprintf (txt, " %+.0f \0", meter_read_value); + lenchk = strlen(txt); + font = get_font(); + charwid = char_widths[font]; + x_offset = charwid * lenchk / 2; + lcd.SetTextColor (text_colour); + lcd.SetBackColor (disc_colour); + if (lenchk > 0 && lenchk < 9) + displaytext (cent_x - x_offset, cent_y + (meter_radius * 11) / 19, font, txt); +} +//bool moving_coil_meter::setup (int cx, int cy, int size, double lo, double hi, double start_ang, double end_ang, +// int scale_ticks, char * units) +void vm_set () //x y size minv maxv min angle max angle, +{ + Speedo.set_colours (SPEEDO_BODY_COLOUR, SPEEDO_DIAL_COLOUR, LCD_COLOR_RED, SPEEDO_TEXT_COLOUR, LCD_COLOR_BLACK); + Speedo.setup (SPEEDO_X, SPEEDO_Y, SPEEDO_SIZE, 0.0, 12.0, 1.25 * PI, -0.25 * PI , 12, "MPH", ONE_DP); + Voltmeter.set_colours (LCD_COLOR_BLACK, LCD_COLOR_WHITE, LCD_COLOR_RED, LCD_COLOR_BLUE, LCD_COLOR_MAGENTA); + Voltmeter.setup (VOLTMETER_X, VOLTMETER_Y, V_A_SIZE, 22.0, 59.0, 1.25 * PI, -0.25 * PI , 30, "V", ONE_DP); + Powermeter.set_colours (LCD_COLOR_BLACK, LCD_COLOR_WHITE, LCD_COLOR_RED, LCD_COLOR_BLUE, LCD_COLOR_BLUE); + Powermeter.setup (AMMETER_X, AMMETER_Y, V_A_SIZE, -1400.0, 1400.0, 1.25 * PI, -0.25 * PI , 14, "Watt", NO_DPS); +} + +void update_meters (double speed, double current, double voltage) +{ + Powermeter.set_value(voltage * current); + Voltmeter.set_value (voltage); + Speedo.set_value (speed); +} + + + +struct rect { struct point a, b; } ; + +struct butt_on { + struct rect area; + int border_colour, body_colour; + bool in_use, pressed;//, released; + char txt1[12]; + char txt2[12]; +} ; + +struct butt_on 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) +{ + int x; + a.count = 0; + a.sli = false; + for (x = 0; x < MAX_TOUCHES; x++) + a.ky[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.ky[a.count].keynum = but; + a.ky[a.count].x = TS_State.touchX[h]; + a.ky[a.count].y = TS_State.touchY[h]; + if (but == SLIDER) { + a.sli = true; + a.slider_y = a.ky[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 butt_on & 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 butt_on * 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 butt_on & bu, int body_colour) +{ + bu.body_colour = body_colour; + draw_button (bu); +} + +void setup_button (struct butt_on & 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 butt_on & 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; +} + +bool keyrelease (int key) +{ + bool rv = false; + if (button[key].pressed) { + rv = true; + button[key].pressed = false; + } + return rv; +} +void setpressed (int key, bool torf) +{ + button[key].pressed = torf; +} +void setinuse (int key, bool torf) +{ + button[key].in_use = torf; +} + + +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_BUT], + 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_BUT], + 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_BUT], + 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], SLIDERX, SLIDERY, SLIDERW, SLIDERH, LCD_COLOR_BLUE, LCD_COLOR_MAGENTA, "", "") ; +} + + +void SliderGraphic (struct slide & q) { + int + colr, + oldbgcolr = lcd.GetBackColor (), + oldtxtcolr = lcd.GetTextColor (); + char txt[4]; + txt[1] = 0; + if (q.position > MAX_POS) + q.position = MAX_POS; + if (q.position < MIN_POS) + q.position = MIN_POS; + if (q.position == NEUTRAL_VAL) + q.state = NEUTRAL_DRIFT; + if (q.position > NEUTRAL_VAL) + q.state = REGEN_BRAKE; + if (q.position < NEUTRAL_VAL) + if (q.state == REGEN_BRAKE) { // Ensure transition from BRAKE to RUN passes through NEUTRAL + q.position = NEUTRAL_VAL; + q.state = NEUTRAL_DRIFT; + } + else + q.state = RUN; + if (q.position == MAX_POS) { + if (q.loco_speed < LOCO_HANDBRAKE_ESCAPE_SPEED) + q.state = PARK; + else { + q.state = REGEN_BRAKE; + q.position--; + } + } + if (q.position != q.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, q.oldpos - BUTTON_RAD, SLIDERW - 2, SLIDERW); + lcd.SetTextColor(LCD_COLOR_BLACK); + lcd.FillRect (SLIDERX + (SLIDERW / 2) - 3, 6, 7, SLIDERH - 8); + q.oldpos = q.position; + lcd.SetTextColor(LCD_COLOR_WHITE); + lcd.DrawCircle (CIRC_CTR, q.position, BUTTON_RAD); // seel also FillCircle + lcd.DrawCircle (CIRC_CTR, q.position, BUTTON_RAD - 1); + switch (q.state) { + case RUN: + txt[0] = 'R'; + colr = LCD_COLOR_GREEN; + break; + case NEUTRAL_DRIFT: + txt[0] = 'N'; + colr = LCD_COLOR_BLUE; + break; + case REGEN_BRAKE: + txt[0] = 'B'; + colr = LCD_COLOR_ORANGE; + break; + case PARK: + txt[0] = 'P'; + colr = LCD_COLOR_RED; + break; + default: + txt[0] = 'X'; + colr = LCD_COLOR_CYAN; + } // End of switch + lcd.SetTextColor(colr); + lcd.FillCircle (CIRC_CTR, q.position, BUTTON_RAD - 2); + lcd.SetBackColor (colr); + lcd.SetTextColor(LCD_COLOR_YELLOW); + displaytext(SLIDERX + 17, q.position - 10, 4, txt); // largest font + lcd.SetBackColor (LCD_COLOR_BLACK); + } // End of else + lcd.SetTextColor (oldtxtcolr); + lcd.SetBackColor (oldbgcolr); +// pc.printf ("SliderG %d, %d, %d\r\n", q.position, q.oldpos, q.state); +} + + + +