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

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers touch_handler.cpp Source File

touch_handler.cpp

00001 #include "mbed.h"
00002 #include "Electric_Loco.h"
00003 #include "TS_DISCO_F746NG.h"
00004 #include "LCD_DISCO_F746NG.h"
00005 
00006 /**
00007 void    read_keypresses    (struct ky_bd & a)
00008 Sets values in struct ky_bd, containing :
00009         struct  ky_bd   {   int count,  slider_y; keystr key[MAX_TOUCHES + 1];   bool  sli;   }  ;
00010             struct  keystr  {   int keynum; int x;  int y;  }   ;
00011     sets a.count to number of fingers found pressing buttons
00012     fills a.key[].keynum with list of 'a.count' button return codes
00013     fills corresponding a.key[].x and a.key[].y with finger coordinates
00014     if button is SLIDER_BUTTON
00015         sets a.sli true else sets false
00016         sets a.slider_y with new slider y coordinate - 0 at top
00017 */
00018 extern  STM3_ESC_Interface    My_STM3_ESC_boards   ;
00019 extern  void    throttle    (double p)  ;            // New Apr 2018 ; servo adjusts throttle lever on Honda GX120
00020 extern  void    read_keypresses    (struct ky_bd & a)   ;
00021 extern  void    draw_button_hilight     (int but, int colour)   ;
00022 extern  void    draw_button (struct button_specs & bu, int body_colour) ;
00023 extern  void    horn    (int which, int onoff)  ;
00024 
00025 extern  Serial  pc;
00026 /**
00027 int     screen_touch_handler::viscous_drag   (int up_viscosity, int dn_viscosity)    ;
00028     Usage
00029         position = viscous_drag (a, b);
00030     Uses latest slider_y and present 'position'
00031     Returns a value for new position moved in direction by amount determined by difference but reduced more for high viscosity
00032     This allows for different rates of control movement for rise and fall
00033 */
00034 int     screen_touch_handler::viscous_drag   (int ip, double up_drag, double dn_drag)    {
00035     int s = (ip - position);    //  ip is final destination position of slider on scale
00036     if  (!s)            //  If no movement
00037         return  position;
00038     int rv;
00039     double  d = (double) s;
00040     if  (up_drag < 0.1) up_drag = 0.1;
00041     if  (dn_drag < 0.1) dn_drag = 0.1;  //  avoiding DIV0 errors
00042     if  (s < 0) {   //  Finger has moved up the slider
00043         rv = position - 1 + (int)(d / up_drag); 
00044     }
00045     if  (s > 0) {   //  Finger has moved down the slider
00046         rv = position + 1 + (int)(d / dn_drag);
00047     }
00048     return  rv;
00049 }
00050 
00051 void    screen_touch_handler::flush   ()    {   //  clear keyboard buffers
00052     kybd_a.count    = kybd_b.count  = 0;
00053     for (int i = 0; i <= MAX_TOUCHES; i++)  {
00054         kybd_a.key[i].keynum    = kybd_b.key[i].keynum = 0;
00055     }
00056 }
00057 /*
00058 Dealing with Keys Pressed
00059     This time   and Last time   AUTOREPEAT
00060     This time   and !Last time  NEW_PRESS
00061     !This time  and Last time   NEW_RELEASE
00062     !This time  and !Last time  not detectable as key not in either list
00063 */
00064 
00065 /**
00066 bool    in_list  (struct ky_bd & a, int key)
00067 Scans current keyboard buffer searching for 'key'.
00068 Returns true if found, false otherwise
00069 */
00070 bool    screen_touch_handler::in_list  (struct ky_bd & a, int key)
00071 {
00072     int i = 0;
00073     while   (i < a.count)
00074         if  (key == a.key[i++].keynum)
00075             return  true;
00076     return  false;
00077 }
00078 
00079 void    screen_touch_handler::motor_power    ()  {  //  uses position to set motor volts and amps and Honda throttle
00080     int b = NEUTRAL_VAL - position;    //  now got integer going positive for increasing power demand
00081     double  torque_req = ((double) b) / (double)(NEUTRAL_VAL - MIN_POS);  //  in range 0.0 to 1.0
00082     if  (torque_req < 0.0)  torque_req = 0.0;
00083     if  (torque_req > 1.0)  torque_req = 1.0;
00084 //                pc.printf   ("torque_rec = %.3f, last_V = %.3f\r\n", torque_req, last_V);
00085     My_STM3_ESC_boards.set_I_limit (torque_req);
00086     if  (torque_req < 0.05) {
00087         My_STM3_ESC_boards.set_V_limit (My_STM3_ESC_boards.last_V / 2.0);
00088         throttle    (torque_req * 6.0);
00089     }
00090     else    {   //  torque_rec >= 0.05
00091         throttle    (0.3 + (torque_req / 2.0));
00092         if  (My_STM3_ESC_boards.last_V < 0.99)
00093             My_STM3_ESC_boards.set_V_limit (My_STM3_ESC_boards.last_V + 0.05);   //  ramp voltage up rather than slam to max
00094     }   //  endof if/else  (torque_req < 0.05) {
00095 }
00096 
00097 
00098 void    screen_touch_handler::HandleFingerInput   ()    {
00099     int key;
00100     if  (present_kybd == &kybd_b)    {       //  swap keyboard buffers
00101         present_kybd = &kybd_a;
00102         previous_kybd = &kybd_b;
00103     }   else    {
00104         present_kybd = &kybd_b;
00105         previous_kybd = &kybd_a;
00106     }
00107     read_keypresses   (*present_kybd);
00108 
00109 //    slider_state_machine    (); //  Takes care of all actions required of slider
00110 
00111 //void    screen_touch_handler::slider_state_machine    ()  {
00112     int old_position = position;    //  Used at end to decide if screen update required
00113     switch  (next_state)    {
00114 
00115         case    NEUTRAL_DRIFT:  //  slider is at 'N', loco not being driven or braked but may well be rolling
00116             if  (present_kybd->sli && previous_kybd->sli) {   //  finger is definitely on slider, found this time and last time
00117                 if  (present_kybd->slider_y < NEUTRAL_VAL)
00118                     next_state = INTO_RUN;
00119                 if  (present_kybd->slider_y > NEUTRAL_VAL)
00120                     next_state = INTO_REGEN_BRAKE;
00121             }
00122             break;        //    endof case    NEUTRAL_DRIFT
00123 
00124         case    INTO_NEUTRAL_DRIFT:
00125             My_STM3_ESC_boards.set_I_limit (0.0);  
00126             My_STM3_ESC_boards.set_V_limit (0.0);  
00127             throttle    (0.0);                      //  Honda revs to tickover
00128             position = NEUTRAL_VAL;     //  'position' is copy of slider_y after application of any viscous damping
00129             next_state = NEUTRAL_DRIFT;
00130             break;
00131 
00132         case    INTO_RUN:   //  cut motor power and set direction of travel
00133             if  (present_kybd->sli) {   //  finger is on slider
00134                 throttle    (0.33);
00135                 if  (direction) My_STM3_ESC_boards.message  ("fw\r");   //  Forward run command
00136                 else            My_STM3_ESC_boards.message  ("re\r");   //  Reverse run command
00137                 next_state  = RUN;
00138             }
00139             break;        //    endof case    INTO_RUN
00140 
00141         case    INTO_REGEN_BRAKE:   //  cut motor power and set 'rb'
00142             My_STM3_ESC_boards.message  ("rb\r");   //  Regen Brake command
00143             throttle    (0.0);                      //  Wind Honda engine revs down to tickover
00144             next_state  = REGEN_BRAKE;
00145             break;        //    endof case    INTO_REGEN_BRAKE
00146 
00147         case    REGEN_BRAKE:    //  established in regenerative braking mode, loco may or may not be rolling
00148             if  (present_kybd->sli) {   //  finger is on slider. No action without finger
00149                 if (position != present_kybd->slider_y)   {   //  update braking effort according to finger movement
00150                     position = viscous_drag (present_kybd->slider_y, 5.0, 5.0);
00151                     if  (position <= NEUTRAL_VAL)       //  if position risen out of REGEN_BRAKE region
00152                         next_state = INTO_NEUTRAL_DRIFT;
00153                     else    {       //  position is within REGEN_BRAKE area
00154                         double  brake_effort = ((double)(position - NEUTRAL_VAL) / (double)(MAX_POS - NEUTRAL_VAL));
00155                         //  brake_effort normalised to range 0.0 to 1.0
00156                         brake_effort *= 0.98;  //  upper limit to braking effort, observed effect before was quite fierce
00157                         My_STM3_ESC_boards.set_V_limit (sqrt(brake_effort));   //  sqrt gives more linear feel to control
00158                         My_STM3_ESC_boards.set_I_limit (1.0);
00159                     }   //  endof else position is within REGEN_BRAKE area
00160                 }       //  endof if finger moved
00161             }           //  endof finger is on slider
00162             break;        //    endof case    REGEN_BRAKE
00163 
00164         case    RUN:            //  remains in this state while finger remains on slider in run range. Drive effort determined by finger position
00165             if  (My_STM3_ESC_boards.last_V < 0.99)
00166                 My_STM3_ESC_boards.set_V_limit (My_STM3_ESC_boards.last_V + 0.05);   //  ramp voltage up rather than slam to max
00167             if  (present_kybd->sli) {   //  finger is on slider
00168                 if (position != present_kybd->slider_y)   {   //  update driving power according to finger movement
00169                     position = viscous_drag (present_kybd->slider_y, 45.0, 20.0);
00170                     if  (position >= NEUTRAL_VAL)       //  if position falen below RUN region
00171                         next_state = INTO_NEUTRAL_DRIFT;
00172                     else               //  Finger is still in RUN range
00173                         motor_power ();     //  class member already has position, sets volts, amps and throttle
00174                 }       //  endof update driving power according to finger movement
00175             }           //  endof finger is on slider
00176             else    {   //  finger not on slider
00177                 throttle    (0.0);      //  Honda revs down to tickover
00178                 next_state = RUN_DOWN;
00179             }
00180             break;        //    endof case    RUN
00181 
00182         case    RUN_DOWN:       //  if finger removed during RUN, slider is to auto-glide back down to 'N'
00183             if  (present_kybd->sli)     //  finger is on slider
00184                     next_state  = RUN;
00185             else    {                   //  finger is not on slider
00186                 position = viscous_drag (NEUTRAL_VAL, 45.0, 20.0);
00187                 if  (position >= NEUTRAL_VAL)   
00188                     next_state = INTO_NEUTRAL_DRIFT;
00189                 else
00190                     motor_power ();
00191             }
00192             break;        //    endof RUN_DOWN
00193 
00194     }   //  endof       switch  (next_state)    {
00195 
00196     if  (position != old_position)  {   //  partial screen rewrite is required
00197         DrawSlider  ();
00198     }
00199 //}   //  endof   void    slider_state_machine    ()  {
00200 
00201 
00202     if  (present_kybd->count || previous_kybd->count)   {   //  at least one key pressed this time or last time
00203 
00204         for (int i = 0; i < present_kybd->count; i++)   {   //  PRESENT Do for all keys pressed on this pass
00205             key = present_kybd->key[i].keynum;
00206             if  (in_list(*previous_kybd, key))   {           //  AUTOREPEAT  This key is being pressed now and last time also
00207 //                pc.printf   ("Autorep key %d\r\n", key);
00208             }           //  endof   AUTOREPEAT  This key is being pressed now and last time also
00209             else    {   //  NEW_PRESS key is a new keypress
00210 //                pc.printf   ("New Press %d\r\n", key);
00211                 draw_button_hilight     (key, LCD_COLOR_YELLOW)  ;
00212                 switch  (key)    {    //  Handle new touch screen button presses here - single action per press, not autorepeat
00213                     case    SLIDER_BUTTON:  //  All slider action handled in state machine above
00214                         break;
00215                     case    SPEEDO_BUTTON:  //  No action currently assigned to speedo button
00216                         break;
00217                     case    VMETER_BUTTON:  //  Turn on high tone horn
00218                         horn    (HI_HORN, 1);
00219                         break;
00220                     case    AMETER_BUTTON:  //  Turn on low tone horn
00221                         horn    (LO_HORN, 1);
00222                         break;
00223                     default:
00224                         pc.printf   ("Unhandled keypress %d\r\n", key);
00225                         break;
00226                 }       //  endof   switch  (key) endof Handle new touch screen button presses here - single action per press, not autorepeat
00227             }           //  endof   NEW_PRESS key is a new keypress
00228         }       //  endof     PRESENT Do for all keys pressed on this pass
00229 
00230         for (int i = 0; i < previous_kybd->count; i++)   {   //  Do for all keys pressed on previous pass
00231             key = previous_kybd->key[i].keynum;
00232             if  (!in_list(*present_kybd, key))   {           //  NEW_RELEASE
00233 //                pc.printf   ("New Release %d\r\n", key);
00234                 draw_button_hilight     (key, LCD_COLOR_DARKBLUE)  ;
00235                 switch  (key)    {    //  Handle new touch screen button RELEASEs here - single action per press, not autorepeat
00236                     case    SLIDER_BUTTON:  //
00237                         break;
00238                     case    SPEEDO_BUTTON:  //
00239                         break;
00240                     case    VMETER_BUTTON:  //
00241                         horn    (HI_HORN, 0);    //  Turn hi-tone horn off   (voltmeter key)
00242                         break;
00243                     case    AMETER_BUTTON:  //
00244                         horn    (LO_HORN, 0);    //  Turn lo-tone horn off   (powermeter key)
00245                         break;
00246                     default:
00247                         pc.printf   ("Unhandled key release %d\r\n", key);
00248                         break;
00249                 }       //  endof   switch  (button)
00250             }                                               //  endof   NEW_RELEASE
00251 /*            else    {     //  DO NOT NEED SECOND FIND OF AUTOREPEAT
00252                 pc.printf   ("Autorep2\r\n");
00253             }*/
00254         }       //  endof     Do for all keys pressed on previous pass
00255     }           //  endof   at least one key pressed this time or last time
00256     else    {   //  no keys being pressed on this pass or previous pass
00257 //        pc.printf   ("no key being pressed\r\n");
00258     }           //  endof   no keys being pressed on this pass or previous pass
00259 }       //  endof   void    screen_touch_handler::HandleFingerInput   ()    {
00260 
00261     screen_touch_handler::screen_touch_handler  ()  {   //  default constructor
00262         present_kybd    = & kybd_a;
00263         previous_kybd   = & kybd_b;
00264         oldpos  = 0;
00265         position    = MAX_POS - 2;
00266         next_state  = INTO_REGEN_BRAKE;
00267         flush   ();
00268     }
00269