Dual Brushless Motor ESC, 10-62V, up to 50A per motor. Motors ganged or independent, multiple control input methods, cycle-by-cycle current limit, speed mode and torque mode control. Motors tiny to kW. Speed limit and other parameters easily set in firmware. As used in 'The Brushless Brutalist' locomotive - www.jons-workshop.com. See also Model Engineer magazine June-October 2019.

Dependencies:   mbed BufferedSerial Servo PCT2075 FastPWM

Update 17th August 2020 Radio control inputs completed

Revision:
16:d1e4b9ad3b8b
Parent:
14:acaa1add097b
Child:
17:cc9b854295d6
--- a/cli_BLS_nortos.cpp	Sat Nov 30 18:40:30 2019 +0000
+++ b/cli_BLS_nortos.cpp	Tue Jun 09 09:20:19 2020 +0000
@@ -24,21 +24,20 @@
 #include <cctype>
 using namespace std;
 
-extern  eeprom_settings     mode     ;
+extern  eeprom_settings     user_settings     ;
 extern  error_handling_Jan_2019     ESC_Error    ;         //  Provides array usable to store error codes.
 extern  int     WatchDog;           //  from main
 extern  bool    WatchDogEnable;     //  from main
-extern  double  rpm2mph ;
+extern  bool    read_temperature    (float & t) ;   //  from main March 2020
 
 extern  brushless_motor MotorA, MotorB;     //  Controlling two motors together or individually
-extern  char   const_version_string[]   ;
+extern  const char *    get_version    ()  ;    //  Need this as extern const char can not be made to work. This returns & const_version_string
 
 extern  BufferedSerial com2, pc;            //  The two com ports used. There is also an unused com port, com3 setup @ 1200 baud
-extern  void    setVI   (double v, double i)  ;     //  Set motor voltage limit and current limit
+extern  void    setVI_both   (double v, double i)  ;     //  Set motor voltage limit and current limit
 extern  double  Read_DriverPot  ();
 extern  double  Read_BatteryVolts   ();
-extern  void    mode_set_both_motors   (int mode, double val)  ;   //  called from cli to set fw, re, rb, hb
-extern  void    rcin_report ()  ;
+extern  void    mode_set_motors_both   (int mode)  ;   //  called from cli to set fw, re, rb, hb
 
 //  All void    func    (struct parameters &)  ; functions addressed by command line interpreter are together below here
 
@@ -49,12 +48,14 @@
 */
 void    ver_cmd (struct parameters & a)
 {
-    if  (a.source == SOURCE_PC)
-        pc.printf   ("Version %s\r\n", const_version_string);
+    if  (a.source == SOURCE_PC) {
+        pc.printf   ("Version [%s]\r\n", get_version());
+    }
     else    {
         if  (a.source == SOURCE_TS)
-            if (a.respond)     //  Only respond if this board addressed
-                a.com->printf   ("%s\r", const_version_string);
+            if (a.respond)  {     //  Only respond if this board addressed
+                a.com->printf   ("%s\r", get_version());
+            }
         else
             pc.printf   ("Crap source %d in ver_cmd\r\n", a.source);
     }
@@ -78,28 +79,13 @@
 void    null_cmd (struct parameters & a)
 {
     if  (a.respond) 
-        a.com->printf   ("At null_cmd, board ID %c\r\n", mode.rd(BOARD_ID));
+        a.com->printf   ("Board ID %c\r\n", user_settings.rd(BOARD_ID));
 }
 
-#ifdef  USING_DC_MOTORS
-/**
-void    mt_cmd (struct parameters & a)
-    PC Only
-    Responds YES, causes action NO
-    report_motor_types  ()      //  Reports 'Brushless' if Hall inputs read 1 to 6, 'DC' if no Hall sensors connected, therefore DC motor assumed
-*/
-void    mt_cmd (struct parameters & a)
-{
-    if  (a.source == SOURCE_PC)
-        pc.printf   ("Mot A is %s, Mot B is %s\r\n", MotorA.dc_motor ? "DC":"Brushless", MotorB.dc_motor ? "DC":"Brushless");
-    else
-        pc.printf   ("Wrong use of mt_cmd\r\n");
-}
-#endif
 
 /**
 *   void    rdi_cmd (struct parameters & a)  //  read motor currents (uint32_t) and BatteryVolts (double)
-*/
+
 void    rdi_cmd (struct parameters & a)  //  read motor currents (uint32_t) and BatteryVolts (double)
 {   //  Voltage reading true volts, currents only useful as relative values
     if  (a.respond) 
@@ -107,16 +93,16 @@
         a.com->printf ("rdi%.1f %.1f %.1f\r%s", MotorA.Idbl, MotorB.Idbl, Read_BatteryVolts  (), a.source == SOURCE_PC ? "\n" : "");
           //  Format good to be unpicked by cli in touch screen controller
 }
-
+*/
 /**
 *   void    rvi_cmd (struct parameters & a)  //  read last normalised motor voltage and current values sent to pwms
 *
 */
-void    rvi_cmd (struct parameters & a)  //  read last normalised values sent to pwms
-{
-    if  (a.respond) 
-        a.com->printf ("rvi%.2f %.2f %.2f %.2f\r%s", MotorA.last_V, MotorA.last_I, MotorB.last_V, MotorB.last_I, a.source == SOURCE_PC ? "\n" : "");
-}
+//void    rvi_cmd (struct parameters & a)  //  read last normalised values sent to pwms
+//{
+//    if  (a.respond) 
+//        a.com->printf ("rvi%.2f %.2f %.2f %.2f\r%s", MotorA.last_V, MotorA.last_I, MotorB.last_V, MotorB.last_I, a.source == SOURCE_PC ? "\n" : "");
+//}
 
 /**
 *   void    fw_cmd (struct parameters & a)  //  Forward command
@@ -124,7 +110,9 @@
 */
 void    fw_cmd (struct parameters & a)  //  Forward command
 {
-    mode_set_both_motors   (MOTOR_FORWARD, 0.0);
+//    MotorA.set_mode (MOTOR_FORWARD);
+//    MotorB.set_mode (MOTOR_FORWARD);
+    mode_set_motors_both   (MOTOR_FORWARD);
     if  (a.source == SOURCE_PC)
         pc.printf   ("fw\r\n");     //  Show response to action if command from pc terminal
 }
@@ -135,7 +123,7 @@
 */
 void    re_cmd (struct parameters & a)  //  Reverse command
 {
-    mode_set_both_motors   (MOTOR_REVERSE, 0.0);
+    mode_set_motors_both   (MOTOR_REVERSE);
     if  (a.source == SOURCE_PC)
         pc.printf   ("re\r\n");
 }
@@ -146,9 +134,11 @@
 */
 void    rb_cmd (struct parameters & a)      //  Regen brake command
 {
-    mode_set_both_motors   (MOTOR_REGENBRAKE, a.dbl[0] / 100.0);
+    double  tmp = a.dbl[0] / 100.0;
+    MotorA.brake    (tmp);
+    MotorB.brake    (tmp);  //  Corrected May 2020 - previously MotorA twice
     if  (a.source == SOURCE_PC)
-        pc.printf   ("rb %.2f\r\n", a.dbl[0] / 100.0);
+        pc.printf   ("rb %.2f\r\n", tmp);
 }
 
 /**
@@ -156,136 +146,72 @@
 *   Broadcast to all STM3_ESC boards, required to ACT but NOT respond
 *
 *   NOTE    Jan 2019 Hand brake not implemented
-*
+*   May 2020 - Implemented, but not very good
 */
 void    hb_cmd (struct parameters & a)      //  Hand brake command
 {
+    double  tmp;
+    if  (a.numof_dbls != 0)  tmp = a.dbl[0] / 100.0;    //  a.numof_dbls is int32_t
+    else                    tmp = 0.33;
     if  (a.respond) {
-        a.com->printf   ("numof params = %d\r\n", a.numof_dbls);
-        a.com->printf   ("Hand Brake : First %.3f, second %.3f\r\n", a.dbl[0], a.dbl[1]);
+//        a.com->printf   ("numof params = %d\r\n", a.numof_dbls);
+        a.com->printf   ("Hand Brake : Force 0 to 99 %.0f\r\n", tmp * 100.0);
     }
-    mode_set_both_motors   (MOTOR_HANDBRAKE, 0.0);
+    mode_set_motors_both   (MOTOR_HANDBRAKE);
+    if  (tmp < 0.0)    tmp = 0.0;
+    if  (tmp > 1.0)    tmp = 1.0;
+    setVI_both (tmp / 5.0, 0.99);
 }
 
 
-extern  int numof_eeprom_options2    ;
-extern  struct  optpar const option_list2[]  ;
-/**void    mode_cmd (struct parameters & a)       //  With no params, reads eeprom contents. With params sets eeprom contents
-*   mode_cmd called only from pc comms. No sense calling from Touch Screen Controller
+
+
+/**void    user_settings_cmd (struct parameters & a)       //  With no params, reads eeprom contents. With params sets eeprom contents
+*   user_settings_cmd called only from pc comms. No sense calling from Touch Screen Controller
 *
 *   Called without parameters - Lists to pc terminal current settings
 *
 */
-void    mode19_cmd (struct parameters & a)       //  With no params, reads eeprom contents. With params sets eeprom contents
+void    user_settings_cmd (struct parameters & a)       //  With no params, reads eeprom contents. With params sets eeprom contents
 {
-    char            temps[36];
-    int i;
-    double  topspeed;   //  New Jan 2019 - set max loco speed
-    pc.printf   ("\r\nmode - Set system data in EEPROM - Jan 2019\r\nSyntax 'mode' with no parameters lists current state.\r\n");
-    if  (a.numof_dbls)  {           //  If more than 0 parameters supplied
-        for (i = 0; i < a.numof_dbls; i++)
-            temps[i] = (char)a.dbl[i];          //  recast doubles to char
-        while   (i < 33)
-            temps[i++] = 0;
-        switch  ((int)a.dbl[0]) {
-            case    0:      //  MotorA_dir [0 or 1], MotorB_dir [0 or 1]
-                if  (temps[1] == 0 || temps[1] == 1)
-                    mode.wr(temps[1], MOTADIR);
-                if  (temps[2] == 0 || temps[2] == 1)
-                    mode.wr(temps[2], MOTBDIR);
-                break;
-            case    1:      //  MotorA_poles [4,6,8], MotorB_poles [4,6,8]
-                if  (temps[1] == 4 || temps[1] == 6 || temps[1] == 8)
-                    mode.wr(temps[1], MOTAPOLES);
-                if  (temps[2] == 4 || temps[2] == 6 || temps[2] == 8)
-                    mode.wr(temps[2], MOTBPOLES);
-                break;
-            case    2:      //  MotorA_ current sense resistors [1 to 4], MotorB_ current sense resistors [1 to 4]
-                if  (temps[1] > 0 && temps[1] < 5) 
-                    mode.wr(temps[1], ISHUNTA);     //  Corrected since published
-                if  (temps[2] > 0 && temps[2] < 5)  
-                    mode.wr(temps[2], ISHUNTB);
-                break;
-            case    3:      //  2 Servo1 [0 or 1], Servo2 [0 or 1]
-                if  (temps[1] == 0 || temps[1] == 1)
-                    mode.wr(temps[1], SVO1);
-                if  (temps[2] == 0 || temps[2] == 1)
-                    mode.wr(temps[2], SVO2);
-                break;
-            case    4:      //  3 RCIn1 [0 or 1], RCIn2 [0 or 1]
-                if  (temps[1] == 0 || temps[1] == 1)
-                    mode.wr(temps[1], RCIN1);
-                if  (temps[2] == 0 || temps[2] == 1)
-                    mode.wr(temps[2], RCIN2);
-                break;
-            case    5:      //  4 Board ID '0' to '9'
-                if  (temps[1] <= 9)    //  pointless to compare unsigned integer with zero
-                    mode.wr('0' | temps[1], BOARD_ID);
-                break;
-            case    6:      //  TOP_SPEED
-                topspeed = a.dbl[1];
-                if  (topspeed > 25.0)   topspeed = 25.0;
-                if  (topspeed < 1.0)    topspeed = 1.0;
-                mode.wr((char)(topspeed * 10.0), TOP_SPEED);
-                break;
-            case    7:      //  5 Wheel dia mm, Motor pinion teeth, Wheel gear teeth
-                mode.wr(temps[1], WHEELDIA);
-                mode.wr(temps[2], MOTPIN);
-                mode.wr(temps[3], WHEELGEAR);
-                break;
-            case    8:      //    {2, 5, 2, "Command source 2= COM2 (Touch Screen), 3= Pot, 4= RC Input1, 5= RC Input2"},
-                if  (temps[1] > 1 && temps[1] < 6)
-                    mode.wr(temps[1], COMM_SRC);
-                break;
-            case    83: //  set to defaults
-                mode.set_defaults   ();
-                break;
-            case    9:      //  9 Save settings
-                mode.save   ();
-                pc.printf   ("Saving settings to EEPROM\r\n");
-                break;
-            default:
-                break;
-        }       //  endof   switch
-    }           //  endof   //  If more than 0 parameters supplied
-    else    {
-        pc.printf   ("No Changes\r\n");
-    }
-    pc.printf   ("mode 0\tMotorA_dir [0 or 1]=%d, MotorB_dir [0 or 1]=%d\r\n", mode.rd(MOTADIR), mode.rd(MOTBDIR));
-    pc.printf   ("mode 1\tMotorA_poles [4,6,8]=%d, MotorB_poles [4,6,8]=%d\r\n", mode.rd(MOTAPOLES), mode.rd(MOTBPOLES));
-    pc.printf   ("mode 2\tMotorA I 0R05 sense Rs [1to4]=%d, MotorB I 0R05 sense Rs [1to4]=%d\r\n", mode.rd(ISHUNTA), mode.rd(ISHUNTB));
-    pc.printf   ("mode 3\tServo1 [0 or 1]=%d, Servo2 [0 or 1]=%d\r\n", mode.rd(SVO1), mode.rd(SVO2));
-    pc.printf   ("mode 4\tRCIn1 [0 or 1]=%d, RCIn2 [0 or 1]=%d\r\n", mode.rd(RCIN1), mode.rd(RCIN2));
-    pc.printf   ("mode 5\tBoard ID ['0' to '9']='%c'\r\n", mode.rd(BOARD_ID));
-    pc.printf   ("mode 6\tTop Speed MPH [1.0 to 25.0]=%.1f\r\n", double(mode.rd(TOP_SPEED)) / 10.0);
-    pc.printf   ("mode 7\tWheel dia mm=%d, Motor pinion teeth=%d, Wheel gear teeth=%d\r\n", mode.rd(WHEELDIA), mode.rd(MOTPIN), mode.rd(WHEELGEAR));
-    pc.printf   ("mode 8\tCommand Src [%d] - 2=COM2 (Touch Screen), 3=Pot, 4=RC In1, 5=RC In2\r\n", mode.rd(COMM_SRC));
-    pc.printf   ("mode 83\tSet to defaults\r\n");
-    pc.printf   ("mode 9\tSave settings\r\r\n");
+    user_settings.edit   (a.dbl, a.numof_dbls);
+}
+
+extern  struct  optpar option_list[] ;  //= {
 
+void    brake_eff_set_cmd  (struct parameters & a)  {     //  set brake effectiveness from TS May 2020
+    char    be = (char) a.dbl[0];
+    pc.printf   ("BRAKE_EFFECTIVENESS min = %d, max = %d\r\n", option_list[BRAKE_EFFECTIVENESS].min, option_list[BRAKE_EFFECTIVENESS].max);
+    if  (be > option_list[BRAKE_EFFECTIVENESS].max)   be = option_list[BRAKE_EFFECTIVENESS].max;
+    if  (be < option_list[BRAKE_EFFECTIVENESS].min)   be = option_list[BRAKE_EFFECTIVENESS].min;
+    user_settings.wr(be, BRAKE_EFFECTIVENESS);
+    user_settings.save   ();
+    pc.printf   ("Set brake effectiveness to %d pct\r\n", be);
 }
 
-
-void    ssl_cmd  (struct parameters & a)  {     //  set speed limit NEW and untested July 2019
-    if  (a.dbl[0] > 25.0)   a.dbl[0] = 25.0;
-    if  (a.dbl[0] < 1.0)    a.dbl[0] = 1.0;
-    mode.wr((char)(a.dbl[0] * 10.0), TOP_SPEED);
-    mode.save   ();
+void    ssl_cmd  (struct parameters & a)  {     //  set speed limit NEW and untested July 2019. Stored as speed * 10 to get 1dec place
+    char    sp = (char) (a.dbl[0] * 10.0);
+    if  (sp > option_list[TOP_SPEED].max)   sp = option_list[TOP_SPEED].max;
+    if  (sp < option_list[TOP_SPEED].min)   sp = option_list[TOP_SPEED].min;
+    user_settings.wr(sp, TOP_SPEED);
+    user_settings.save   ();
+    pc.printf   ("Set speed limit to %.1f mph\r\n", a.dbl[0]);
 }
 
-#ifdef  TEMP_SENSOR_ENABLE
-
-extern  uint32_t    last_temperature_count;
 /**
 *   void    temperature_cmd  (struct parameters & a)  {
-*   Few boards have temperature sensor fitted. Non-preferred feature
+*   Few boards have temperature sensor fitted. Now only supports LM75B i2c sensor
 */
-void    temperature_cmd  (struct parameters & a)  {
+void    read_temperature_cmd  (struct parameters & a)  {
+    float   t = -99.25;
     if  (a.respond) {
-        a.com->printf ("tem%c %d\r\n", mode.rd(BOARD_ID), (last_temperature_count / 16) - 50);
+        a.com->printf ("tem%c ", user_settings.rd(BOARD_ID));
+        if  (read_temperature(t))
+            a.com->printf   ("Temperature = %7.3f\r\n", t);
+        else
+            a.com->printf   ("Temp sensor not fitted\r\n");
     }
 }
-#endif
 
 /**
 *void    rpm_cmd (struct parameters & a) //  to report e.g. RPM 1000 1000 ; speed for both motors
@@ -293,18 +219,31 @@
 void    rpm_cmd (struct parameters & a) //  to report e.g. RPM 1000 1000 ; speed for both motors
 {
     if  (a.respond) 
-//        a.com->printf  ("rpm%c %d %d\r%s", mode.rd(BOARD_ID), MotorA.RPM, MotorB.RPM, a.source == SOURCE_PC ? "\n" : "");
-        a.com->printf  ("rpm%c %.0f %.0f\r%s", mode.rd(BOARD_ID), MotorA.dRPM, MotorB.dRPM, a.source == SOURCE_PC ? "\n" : "");
+//        a.com->printf  ("rpm%c %d %d\r%s", user_settings.rd(BOARD_ID), MotorA.RPM, MotorB.RPM, a.source == SOURCE_PC ? "\n" : "");
+        a.com->printf  ("rpm%c %.0f %.0f\r%s", user_settings.rd(BOARD_ID), MotorA.dRPM, MotorB.dRPM, a.source == SOURCE_PC ? "\n" : "");
 }
 
 /**
 *void    mph_cmd (struct parameters & a) //  to report miles per hour
 */
-void    mph_cmd (struct parameters & a) //  to report miles per hour to 1 decimal place
+void    mph_cmd (struct parameters & a) //  to report miles per hour to 1 decimal place - now 2dp May 2020
 {
+    int j = 0;
+    double  speedmph = 0.0;
+    if  (MotorA.exists  ()) {
+        j |= 1;
+        speedmph = MotorA.dMPH;
+    }
+    if  (MotorB.exists  ()) {
+        j |= 2;
+        speedmph += MotorB.dMPH;
+    }
+    if  (j == 3)
+        speedmph /= 2.0;
     if  (a.respond) 
-//        a.com->printf ("mph%c %.1f\r%s", mode.rd(BOARD_ID), (double)(MotorA.RPM + MotorB.RPM) * rpm2mph / 2.0, a.source == SOURCE_PC ? "\n" : "");
-        a.com->printf ("mph%c %.1f\r%s", mode.rd(BOARD_ID), (double)(MotorA.dMPH + MotorB.dMPH) / 2.0, a.source == SOURCE_PC ? "\n" : "");
+//  May 17th 2020 modified line below - removed superfluous cast, upped to 2 decimal places
+//        a.com->printf ("mph%c %.2f\r%s", user_settings.rd(BOARD_ID), speedmph, a.source == SOURCE_PC ? "\n" : "");
+        a.com->printf ("?s%c %.2f\r%s", user_settings.rd(BOARD_ID), speedmph, a.source == SOURCE_PC ? "\n" : "");
 }
 
 /**
@@ -314,7 +253,7 @@
 void    sysV_report (struct parameters & a) //  
 {
     if  (a.respond) 
-        a.com->printf ("?v%c %.1f\r%s", mode.rd(BOARD_ID), Read_BatteryVolts(), a.source == SOURCE_PC ? "\n" : "");
+        a.com->printf ("?v%c %.1f\r%s", user_settings.rd(BOARD_ID), Read_BatteryVolts(), a.source == SOURCE_PC ? "\n" : "");
 }
 
 /**
@@ -323,12 +262,46 @@
 */
 void    sysI_report (struct parameters & a) //  
 {
-    if  (a.respond) //  Calibration, refinement of 6000.0 (not miles out) first guess possible.
-//        a.com->printf ("?i%c %.2f %.2f\r%s", mode_bytes[BOARD_ID], (double)MotorA.I.ave / 6000.0, (double)MotorB.I.ave / 6000.0, a.source == SOURCE_PC ? "\n" : "");
-//        a.com->printf ("?i%c %.2f %.2f\r%s", mode.rd(BOARD_ID), (double)MotorA.I.ave / 6000.0, MotorA.I.dblave2 / 6000.0, a.source == SOURCE_PC ? "\n" : "");
-        a.com->printf ("?i%c %.2f %.2f\r%s", mode.rd(BOARD_ID), MotorA.Idbl, MotorB.Idbl, a.source == SOURCE_PC ? "\n" : "");
+    if  (a.respond)
+        a.com->printf ("?i%c %.2f %.2f\r%s", user_settings.rd(BOARD_ID), MotorA.Idbl, MotorB.Idbl, a.source == SOURCE_PC ? "\n" : "");
 }
 
+/*
+
+New December 2019 - possible for implementation
+    Having implemented radio control inputs and driver pot, there is some sense in moving slider handler from touch screen controller
+    into STM3_ESC code.
+        New instructions to be accepted from touch screen : -
+    {"w", "touch screen new slider touch", slider_touch_cmd},
+    {"x", "updated slider RANGE 0 to 99", slider_touch_position_cmd},   //  max two digits
+    {"y", "touch_screen slider finger lifted clear", slider_untouch_cmd},
+*/
+bool    finger_on_slider = false;
+/**void    slider_touch_cmd (struct parameters & a)
+*
+*   Message from touch screen controller, slider touched
+*/
+void    slider_touch_cmd (struct parameters & a)    {
+    finger_on_slider = true;
+}
+
+/**void    slider_untouch_cmd (struct parameters & a)
+*
+*   Message from touch screen controller, finger taken off slider
+*/
+void    slider_untouch_cmd (struct parameters & a)    {
+    finger_on_slider = false;
+}
+
+/**void    slider_touch_position_cmd (struct parameters & a)
+*
+*   Message from touch screen controller, latest slider touch position
+*/
+void    slider_touch_position_cmd (struct parameters & a)   {
+}
+
+//  End of  New December 2019 
+
 
 /**void    vi_cmd (struct parameters & a)
 *
@@ -336,8 +309,8 @@
 */
 void    vi_cmd (struct parameters & a)
 {
-    setVI   (a.dbl[0] / 100.0, a.dbl[1] / 100.0);
-    pc.printf   ("setVI from %s\r\n", a.source == SOURCE_PC ? "PC" : "Touch Screen");
+    setVI_both   (a.dbl[0] / 100.0, a.dbl[1] / 100.0);
+//    pc.printf   ("setVI_both from %s\r\n", a.source == SOURCE_PC ? "PC" : "Touch Screen");
 }
 
 /**
@@ -370,7 +343,7 @@
 */
 void    kd_cmd (struct parameters & a)  //  kick the watchdog. Reached from TS or pc.
 {
-    WatchDog = WATCHDOG_RELOAD + (mode.rd(BOARD_ID) & 0x0f);   //  Reload watchdog timeout. Counted down @ 8Hz
+    WatchDog = WATCHDOG_RELOAD + (user_settings.rd(BOARD_ID) & 0x0f);   //  Reload watchdog timeout. Counted down @ 8Hz
     WatchDogEnable = true;                          //  Receipt of this command sufficient to enable watchdog
 }
 
@@ -387,8 +360,8 @@
 */
 void    who_cmd (struct parameters & a)     //  Reachable always from pc. Only addressed board responds to TS
 {
-    if  (a.source == SOURCE_PC || mode.rd(BOARD_ID) == a.target_unit)
-        a.com->printf ("who%c\r%s", mode.rd(BOARD_ID), a.source == SOURCE_PC ? "\n" : "");
+    if  (a.source == SOURCE_PC || user_settings.rd(BOARD_ID) == a.target_unit)
+        a.com->printf ("who%c\r%s", user_settings.rd(BOARD_ID), a.source == SOURCE_PC ? "\n" : "");
 }
 
 /**
@@ -396,11 +369,11 @@
 *
 *   For test, reports to pc terminal info about radio control input channels
 */
-void    rcin_pccmd (struct parameters & a)
-{
-    rcin_report ();
-}
-
+//void    rcin_pccmd (struct parameters & a)
+//{
+//    rcin_report ();
+//}
+/*
 void    scmd (struct parameters & a)    //  filter coefficient fiddler
 {
     switch  ((int)a.dbl[0]) {
@@ -416,10 +389,6 @@
         case    4:
             MotorA.sdbl[4] = MotorB.sdbl[4] = a.dbl[1];
             break;
-        case    5:
-            MotorA.set_speed    (a.dbl[1]);
-            MotorB.set_speed    (a.dbl[1]);
-            break;
         default:
             pc.printf   ("Wrong use of scmd %f\r\n", a.dbl[0]);
     }
@@ -429,9 +398,9 @@
     pc.printf   ("2 %.3f\tP_gain 1.0-1000.0\r\n",   MotorA.sdbl[2]);
     pc.printf   ("3 %.3f\tDscale 0.01-0.5\r\n",     MotorA.sdbl[3]);
     pc.printf   ("4 %.3f\tD_gain 1.0-1000.0\r\n",   MotorA.sdbl[4]);
-    pc.printf   ("5 Set target_speed\r\n");
+//    pc.printf   ("5 Set target_speed\r\n");
 }
-
+*/
     struct kb_command  {    //  Commands tabulated as list of these structures as seen below
     const char * cmd_word;              //  points to text e.g. "menu"
     const char * explan;                //  very brief explanation or clue as to purpose of function
@@ -446,7 +415,7 @@
 void    menucmd (struct parameters & a)
 {
     if  (a.respond) {
-        a.com->printf("\r\n\nDual BLDC ESC type STM3 2018-20, Ver %s\r\nAt menucmd function - listing commands, source %s:-\r\n", const_version_string, a.source == SOURCE_PC ? "PC" : "TS");
+        a.com->printf("\r\n\nDual BLDC ESC type STM3 2018-20, Ver %s\r\nAt menucmd function - listing commands, source %s:-\r\n", get_version(), a.source == SOURCE_PC ? "PC" : "TS");
         for(int i = 0; i < a.numof_menu_items; i++)
             a.com->printf("[%s]\t\t%s\r\n", a.command_list[i].cmd_word, a.command_list[i].explan);
         a.com->printf("End of List of Commands\r\n");
@@ -464,23 +433,28 @@
     //  ***** Broadcast commands for all STM3_ESC boards to execute. Boards NOT to send serial response *****
     {"fw", "forward", fw_cmd},
     {"re", "reverse", re_cmd},
-    {"rb", "regen brake 0 to 99 %", rb_cmd},
+    {"rb", "regen brake 0 to 99 %", rb_cmd},    //  max two digits
     {"hb", "hand brake", hb_cmd},
-    {"v", "set motors V percent RANGE 0 to 100", v_cmd},
-    {"i", "set motors I percent RANGE 0 to 100", i_cmd},
-    {"vi", "set motors V and I percent RANGE 0 to 100", vi_cmd},
+    {"v", "set motors V percent RANGE 0 to 99", v_cmd},
+    {"i", "set motors I percent RANGE 0 to 99", i_cmd},
+    {"vi", "set motors V and I percent RANGE 0 to 99", vi_cmd},
+    {"w", "touch screen new slider touch", slider_touch_cmd},
+    {"x", "updated slider RANGE 0 to 99", slider_touch_position_cmd},
+    {"y", "touch_screen slider finger lifted clear", slider_untouch_cmd},
     {"kd", "kick the dog, reloads WatchDog", kd_cmd},
+    {"ssl", "set speed limit e.g. 10.7", ssl_cmd},              //  NEW July 2019
+    {"sbe", "set brake effectiveness 5 to 90 percent", brake_eff_set_cmd},              //  NEW May 2020
     //  ***** Endof Broadcast commands for all STM3_ESC boards to execute. Boards NOT to send serial response *****
 
     //  ***** Following are rx'd requests for serial response from addressed STM3_ESC only
     {"?v", "Report system bus voltage", sysV_report},
     {"?i", "Report motor both currents", sysI_report},
     {"who", "search for connected units, e.g. 3who returs 'who3' if found", who_cmd},
-#ifdef  TEMP_SENSOR_ENABLE
-    {"tem", "report temperature", temperature_cmd},
-#endif
+    {"tem", "report temperature", read_temperature_cmd},
     {"mph", "read loco speed miles per hour", mph_cmd},
-    {"ssl", "set speed limit e.g. 10.7", ssl_cmd},              //  NEW July 2019
+    {"?s", "read loco speed miles per hour", mph_cmd},       //  Shorter-hand added 17th May 2020
+//    {"ssl", "set speed limit e.g. 10.7", ssl_cmd},              //  NEW July 2019
+//    {"sbe", "set brake effectiveness 5 to 90 percent", brake_eff_set_cmd},              //  NEW May 2020
 //    {"rvi", "read most recent values sent to pwms", rvi_cmd},
 //    {"rdi", "read motor currents and power voltage", rdi_cmd},
     //  ***** Endof
@@ -494,10 +468,6 @@
 struct  kb_command const pc_command_list[] = {
     {"ls", "Lists available commands", menucmd},
     {"?", "Lists available commands, same as ls", menucmd},
-#ifdef  USING_DC_MOTORS
-    {"mtypes", "report types of motors found", mt_cmd},
-#endif
-    {"s","1-4, RPM and speed filter param", scmd},
     {"pot", "read drivers control pot", pot_cmd},
     {"fw", "forward", fw_cmd},
     {"re", "reverse", re_cmd},
@@ -510,19 +480,18 @@
     {"?i", "Report motor both currents", sysI_report},
     {"?w", "show WatchDog timer contents", wd_report},
     {"who", "search for connected units, e.g. 3who returs 'who3' if found", who_cmd},
-    {"mode", "read or set params in eeprom", mode19_cmd},                                 //  Big change Jan 2019
+    {"us", "read or set user settings in eeprom", user_settings_cmd},                                 //  Big change Jan 2019
     {"ssl", "set speed limit e.g. 10.7", ssl_cmd},              //  NEW July 2019 ONLY HERE FOR TEST, normal use is from Touch Screen only.
+    {"sbe", "set brake effectiveness 5 to 90 percent", brake_eff_set_cmd},              //  NEW May 2020
 //    {"erase", "set eeprom contents to all 0xff", erase_cmd},
-#ifdef  TEMP_SENSOR_ENABLE
-    {"tem", "report temperature", temperature_cmd},                                     //  Reports -50 when sensor not fitted
-#endif
+    {"tem", "report temperature", read_temperature_cmd},                                     //  Reports -50 when sensor not fitted
     {"kd", "kick the dog, reloads WatchDog", kd_cmd},
     {"ver", "Version", ver_cmd},
-    {"rcin", "Report Radio Control Input stuff", rcin_pccmd},
     {"rpm", "read motor pair speeds", rpm_cmd},
     {"mph", "read loco speed miles per hour", mph_cmd},
-    {"rvi", "read most recent values sent to pwms", rvi_cmd},
-    {"rdi", "read motor currents and power voltage", rdi_cmd},
+    {"?s", "read loco speed miles per hour", mph_cmd},
+//    {"rvi", "read most recent values sent to pwms", rvi_cmd},
+//    {"rdi", "read motor currents and power voltage", rdi_cmd},
 //    {"bc", "bogie constants - wheel dia, motor pinion, wheel gear", bogie_constants_report_cmd},
 //    {"gbb", "get bogie bytes from eeprom and report", gbb_cmd},    //  OBSOLETE, replaced by 'gbb'
     {"nu", "do nothing", null_cmd},
@@ -552,8 +521,11 @@
 *
 *   Daft check that class instantiation worked
 */
-void    cli_2019::test ()  {
-    pc.printf   ("At cli2019::test, source %d len %d,\r\n", a.source, a.numof_menu_items);
+void    cli_2019::flush ()  {
+//    char ch;
+    while   (a.com->readable())
+        a.com->getc();
+    //pc.printf   ("At cli2019::test, source %d len %d,\r\n", a.source, a.numof_menu_items);
 }
 
 /**
@@ -567,7 +539,7 @@
 *   Parameters available to functions from 'parameters' struct.
 */
 void    cli_2019::core ()  {    
-    int ch, IAm = mode.rd(BOARD_ID);
+    int ch, IAm = user_settings.rd(BOARD_ID);
     char * pEnd;//, * cmd_line_ptr;
     while  (a.com->readable()) {
         ch = a.com->getc();
@@ -594,17 +566,21 @@
                 for (i = 0; i < a.numof_menu_items; i++)   {   //  Look for input match in command list
                     wrdlen = strlen(commandlist[i].cmd_word);
                     if(strncmp(commandlist[i].cmd_word, cmdline_ptr, wrdlen) == 0 && !isalpha(cmdline_ptr[wrdlen]))  {   //  If match found
-                        for (int k = 0; k < MAX_PARAMS; k++)    {
+                        for (int k = 0; k < MAX_CLI_PARAMS; k++)    {
                             a.dbl[k] = 0.0;
                         }
                         a.position_in_list = i;
                         a.numof_dbls = 0;
+//                                pEnd = cmdline + clindex; // does indeed point to null terminator
                         pEnd = cmdline_ptr + wrdlen;
-                        while   (*pEnd)  {          //  Assemble all numerics as doubles
+//                        while   (*pEnd)  {          //  Assemble all numerics as doubles
+                        while   (*pEnd && a.numof_dbls < MAX_CLI_PARAMS)  {          //  Assemble all numerics as doubles
                             a.dbl[a.numof_dbls++] = strtod    (pEnd, &pEnd);
-                            while   (*pEnd && !isdigit(*pEnd) && '-' != *pEnd && '+' != *pEnd)  {
+                            while   (*pEnd && (pEnd < cmdline + clindex) && *pEnd && !isdigit(*pEnd) && ('.' != *pEnd) && ('-' != *pEnd) && ('+' != *pEnd))  {   //  Can crash cli here with e.g. 'ls -l'
                                 pEnd++;
-                            }
+                            }   //  problem occurs with input such as "- ", or "-a", seemingly anything dodgy following a '-' or a '+'
+                            if  (((*pEnd == '-') || (*pEnd == '+')) &&(!isdigit(*(pEnd+1))) && ('.' !=*(pEnd+1)))
+                                pEnd = cmdline + clindex;   //  fixed by aborting remainder of line
                         }
                         a.respond = a.resp_always;
                         if  (((a.target_unit == BROADCAST) && (IAm == '0')) || (IAm == a.target_unit))