Jon Freeman / Mbed 2 deprecated Brute_TS_Controller_2018_11

Dependencies:   TS_DISCO_F746NG mbed Servo LCD_DISCO_F746NG BSP_DISCO_F746NG QSPI_DISCO_F746NG AsyncSerial FastPWM

Revision:
12:a25bdf135348
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/touch_handler.cpp	Mon Jan 14 16:39:41 2019 +0000
@@ -0,0 +1,269 @@
+#include "mbed.h"
+#include "Electric_Loco.h"
+#include "TS_DISCO_F746NG.h"
+#include "LCD_DISCO_F746NG.h"
+
+/**
+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
+*/
+extern  STM3_ESC_Interface    My_STM3_ESC_boards   ;
+extern  void    throttle    (double p)  ;            // New Apr 2018 ; servo adjusts throttle lever on Honda GX120
+extern  void    read_keypresses    (struct ky_bd & a)   ;
+extern  void    draw_button_hilight     (int but, int colour)   ;
+extern  void    draw_button (struct button_specs & bu, int body_colour) ;
+extern  void    horn    (int which, int onoff)  ;
+
+extern  Serial  pc;
+/**
+int     screen_touch_handler::viscous_drag   (int up_viscosity, int dn_viscosity)    ;
+    Usage
+        position = viscous_drag (a, b);
+    Uses latest slider_y and present 'position'
+    Returns a value for new position moved in direction by amount determined by difference but reduced more for high viscosity
+    This allows for different rates of control movement for rise and fall
+*/
+int     screen_touch_handler::viscous_drag   (int ip, double up_drag, double dn_drag)    {
+    int s = (ip - position);    //  ip is final destination position of slider on scale
+    if  (!s)            //  If no movement
+        return  position;
+    int rv;
+    double  d = (double) s;
+    if  (up_drag < 0.1) up_drag = 0.1;
+    if  (dn_drag < 0.1) dn_drag = 0.1;  //  avoiding DIV0 errors
+    if  (s < 0) {   //  Finger has moved up the slider
+        rv = position - 1 + (int)(d / up_drag); 
+    }
+    if  (s > 0) {   //  Finger has moved down the slider
+        rv = position + 1 + (int)(d / dn_drag);
+    }
+    return  rv;
+}
+
+void    screen_touch_handler::flush   ()    {   //  clear keyboard buffers
+    kybd_a.count    = kybd_b.count  = 0;
+    for (int i = 0; i <= MAX_TOUCHES; i++)  {
+        kybd_a.key[i].keynum    = kybd_b.key[i].keynum = 0;
+    }
+}
+/*
+Dealing with Keys Pressed
+    This time   and Last time   AUTOREPEAT
+    This time   and !Last time  NEW_PRESS
+    !This time  and Last time   NEW_RELEASE
+    !This time  and !Last time  not detectable as key not in either list
+*/
+
+/**
+bool    in_list  (struct ky_bd & a, int key)
+Scans current keyboard buffer searching for 'key'.
+Returns true if found, false otherwise
+*/
+bool    screen_touch_handler::in_list  (struct ky_bd & a, int key)
+{
+    int i = 0;
+    while   (i < a.count)
+        if  (key == a.key[i++].keynum)
+            return  true;
+    return  false;
+}
+
+void    screen_touch_handler::motor_power    ()  {  //  uses position to set motor volts and amps and Honda throttle
+    int b = NEUTRAL_VAL - position;    //  now got integer going positive for increasing power demand
+    double  torque_req = ((double) b) / (double)(NEUTRAL_VAL - MIN_POS);  //  in range 0.0 to 1.0
+    if  (torque_req < 0.0)  torque_req = 0.0;
+    if  (torque_req > 1.0)  torque_req = 1.0;
+//                pc.printf   ("torque_rec = %.3f, last_V = %.3f\r\n", torque_req, last_V);
+    My_STM3_ESC_boards.set_I_limit (torque_req);
+    if  (torque_req < 0.05) {
+        My_STM3_ESC_boards.set_V_limit (My_STM3_ESC_boards.last_V / 2.0);
+        throttle    (torque_req * 6.0);
+    }
+    else    {   //  torque_rec >= 0.05
+        throttle    (0.3 + (torque_req / 2.0));
+        if  (My_STM3_ESC_boards.last_V < 0.99)
+            My_STM3_ESC_boards.set_V_limit (My_STM3_ESC_boards.last_V + 0.05);   //  ramp voltage up rather than slam to max
+    }   //  endof if/else  (torque_req < 0.05) {
+}
+
+
+void    screen_touch_handler::HandleFingerInput   ()    {
+    int key;
+    if  (present_kybd == &kybd_b)    {       //  swap keyboard buffers
+        present_kybd = &kybd_a;
+        previous_kybd = &kybd_b;
+    }   else    {
+        present_kybd = &kybd_b;
+        previous_kybd = &kybd_a;
+    }
+    read_keypresses   (*present_kybd);
+
+//    slider_state_machine    (); //  Takes care of all actions required of slider
+
+//void    screen_touch_handler::slider_state_machine    ()  {
+    int old_position = position;    //  Used at end to decide if screen update required
+    switch  (next_state)    {
+
+        case    NEUTRAL_DRIFT:  //  slider is at 'N', loco not being driven or braked but may well be rolling
+            if  (present_kybd->sli && previous_kybd->sli) {   //  finger is definitely on slider, found this time and last time
+                if  (present_kybd->slider_y < NEUTRAL_VAL)
+                    next_state = INTO_RUN;
+                if  (present_kybd->slider_y > NEUTRAL_VAL)
+                    next_state = INTO_REGEN_BRAKE;
+            }
+            break;        //    endof case    NEUTRAL_DRIFT
+
+        case    INTO_NEUTRAL_DRIFT:
+            My_STM3_ESC_boards.set_I_limit (0.0);  
+            My_STM3_ESC_boards.set_V_limit (0.0);  
+            throttle    (0.0);                      //  Honda revs to tickover
+            position = NEUTRAL_VAL;     //  'position' is copy of slider_y after application of any viscous damping
+            next_state = NEUTRAL_DRIFT;
+            break;
+
+        case    INTO_RUN:   //  cut motor power and set direction of travel
+            if  (present_kybd->sli) {   //  finger is on slider
+                throttle    (0.33);
+                if  (direction) My_STM3_ESC_boards.message  ("fw\r");   //  Forward run command
+                else            My_STM3_ESC_boards.message  ("re\r");   //  Reverse run command
+                next_state  = RUN;
+            }
+            break;        //    endof case    INTO_RUN
+
+        case    INTO_REGEN_BRAKE:   //  cut motor power and set 'rb'
+            My_STM3_ESC_boards.message  ("rb\r");   //  Regen Brake command
+            throttle    (0.0);                      //  Wind Honda engine revs down to tickover
+            next_state  = REGEN_BRAKE;
+            break;        //    endof case    INTO_REGEN_BRAKE
+
+        case    REGEN_BRAKE:    //  established in regenerative braking mode, loco may or may not be rolling
+            if  (present_kybd->sli) {   //  finger is on slider. No action without finger
+                if (position != present_kybd->slider_y)   {   //  update braking effort according to finger movement
+                    position = viscous_drag (present_kybd->slider_y, 5.0, 5.0);
+                    if  (position <= NEUTRAL_VAL)       //  if position risen out of REGEN_BRAKE region
+                        next_state = INTO_NEUTRAL_DRIFT;
+                    else    {       //  position is within REGEN_BRAKE area
+                        double  brake_effort = ((double)(position - NEUTRAL_VAL) / (double)(MAX_POS - NEUTRAL_VAL));
+                        //  brake_effort normalised to range 0.0 to 1.0
+                        brake_effort *= 0.98;  //  upper limit to braking effort, observed effect before was quite fierce
+                        My_STM3_ESC_boards.set_V_limit (sqrt(brake_effort));   //  sqrt gives more linear feel to control
+                        My_STM3_ESC_boards.set_I_limit (1.0);
+                    }   //  endof else position is within REGEN_BRAKE area
+                }       //  endof if finger moved
+            }           //  endof finger is on slider
+            break;        //    endof case    REGEN_BRAKE
+
+        case    RUN:            //  remains in this state while finger remains on slider in run range. Drive effort determined by finger position
+            if  (My_STM3_ESC_boards.last_V < 0.99)
+                My_STM3_ESC_boards.set_V_limit (My_STM3_ESC_boards.last_V + 0.05);   //  ramp voltage up rather than slam to max
+            if  (present_kybd->sli) {   //  finger is on slider
+                if (position != present_kybd->slider_y)   {   //  update driving power according to finger movement
+                    position = viscous_drag (present_kybd->slider_y, 45.0, 20.0);
+                    if  (position >= NEUTRAL_VAL)       //  if position falen below RUN region
+                        next_state = INTO_NEUTRAL_DRIFT;
+                    else               //  Finger is still in RUN range
+                        motor_power ();     //  class member already has position, sets volts, amps and throttle
+                }       //  endof update driving power according to finger movement
+            }           //  endof finger is on slider
+            else    {   //  finger not on slider
+                throttle    (0.0);      //  Honda revs down to tickover
+                next_state = RUN_DOWN;
+            }
+            break;        //    endof case    RUN
+
+        case    RUN_DOWN:       //  if finger removed during RUN, slider is to auto-glide back down to 'N'
+            if  (present_kybd->sli)     //  finger is on slider
+                    next_state  = RUN;
+            else    {                   //  finger is not on slider
+                position = viscous_drag (NEUTRAL_VAL, 45.0, 20.0);
+                if  (position >= NEUTRAL_VAL)   
+                    next_state = INTO_NEUTRAL_DRIFT;
+                else
+                    motor_power ();
+            }
+            break;        //    endof RUN_DOWN
+
+    }   //  endof       switch  (next_state)    {
+
+    if  (position != old_position)  {   //  partial screen rewrite is required
+        DrawSlider  ();
+    }
+//}   //  endof   void    slider_state_machine    ()  {
+
+
+    if  (present_kybd->count || previous_kybd->count)   {   //  at least one key pressed this time or last time
+
+        for (int i = 0; i < present_kybd->count; i++)   {   //  PRESENT Do for all keys pressed on this pass
+            key = present_kybd->key[i].keynum;
+            if  (in_list(*previous_kybd, key))   {           //  AUTOREPEAT  This key is being pressed now and last time also
+//                pc.printf   ("Autorep key %d\r\n", key);
+            }           //  endof   AUTOREPEAT  This key is being pressed now and last time also
+            else    {   //  NEW_PRESS key is a new keypress
+//                pc.printf   ("New Press %d\r\n", key);
+                draw_button_hilight     (key, LCD_COLOR_YELLOW)  ;
+                switch  (key)    {    //  Handle new touch screen button presses here - single action per press, not autorepeat
+                    case    SLIDER_BUTTON:  //  All slider action handled in state machine above
+                        break;
+                    case    SPEEDO_BUTTON:  //  No action currently assigned to speedo button
+                        break;
+                    case    VMETER_BUTTON:  //  Turn on high tone horn
+                        horn    (HI_HORN, 1);
+                        break;
+                    case    AMETER_BUTTON:  //  Turn on low tone horn
+                        horn    (LO_HORN, 1);
+                        break;
+                    default:
+                        pc.printf   ("Unhandled keypress %d\r\n", key);
+                        break;
+                }       //  endof   switch  (key) endof Handle new touch screen button presses here - single action per press, not autorepeat
+            }           //  endof   NEW_PRESS key is a new keypress
+        }       //  endof     PRESENT Do for all keys pressed on this pass
+
+        for (int i = 0; i < previous_kybd->count; i++)   {   //  Do for all keys pressed on previous pass
+            key = previous_kybd->key[i].keynum;
+            if  (!in_list(*present_kybd, key))   {           //  NEW_RELEASE
+//                pc.printf   ("New Release %d\r\n", key);
+                draw_button_hilight     (key, LCD_COLOR_DARKBLUE)  ;
+                switch  (key)    {    //  Handle new touch screen button RELEASEs here - single action per press, not autorepeat
+                    case    SLIDER_BUTTON:  //
+                        break;
+                    case    SPEEDO_BUTTON:  //
+                        break;
+                    case    VMETER_BUTTON:  //
+                        horn    (HI_HORN, 0);    //  Turn hi-tone horn off   (voltmeter key)
+                        break;
+                    case    AMETER_BUTTON:  //
+                        horn    (LO_HORN, 0);    //  Turn lo-tone horn off   (powermeter key)
+                        break;
+                    default:
+                        pc.printf   ("Unhandled key release %d\r\n", key);
+                        break;
+                }       //  endof   switch  (button)
+            }                                               //  endof   NEW_RELEASE
+/*            else    {     //  DO NOT NEED SECOND FIND OF AUTOREPEAT
+                pc.printf   ("Autorep2\r\n");
+            }*/
+        }       //  endof     Do for all keys pressed on previous pass
+    }           //  endof   at least one key pressed this time or last time
+    else    {   //  no keys being pressed on this pass or previous pass
+//        pc.printf   ("no key being pressed\r\n");
+    }           //  endof   no keys being pressed on this pass or previous pass
+}       //  endof   void    screen_touch_handler::HandleFingerInput   ()    {
+
+    screen_touch_handler::screen_touch_handler  ()  {   //  default constructor
+        present_kybd    = & kybd_a;
+        previous_kybd   = & kybd_b;
+        oldpos  = 0;
+        position    = MAX_POS - 2;
+        next_state  = INTO_REGEN_BRAKE;
+        flush   ();
+    }
+