Code for 'Smart Regulator' featured in 'Model Engineer', November 2020 on. Contains all work to August 2020 including all code described. Top level algorithm development is quite spares, leaving some work for you! Any questions - jon@jons-workshop.com

Dependencies:   mbed BufferedSerial Servo2 PCT2075 I2CEeprom FastPWM

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers cli.cpp Source File

cli.cpp

00001 /*
00002 Command Line Interpreter code module.
00003 Purpose -
00004     Provides easy interface to pc terminal programme for use during programme development, debug etc.
00005     Also usable as comms subsystem in finished code for accepting commands, reporting data etc.
00006 */
00007 #include "mbed.h"
00008 #include "field.h"
00009 #include "Alternator.h"
00010 #include "BufferedSerial.h"
00011 #include <cctype>
00012 using namespace std;
00013 
00014 ee_settings_2020 user_settings     ;
00015 
00016 extern  BufferedSerial pc;
00017 extern  void    maketable   ()  ;
00018 extern  void    query_system    (struct parameters & a)    ;
00019 extern  uint32_t    ReadEngineRPM  ()   ;
00020 extern  double  Read_Link_Volts   ()  ;
00021 extern  double  Read_Field_Volts   ()  ;
00022 extern  double  Read_Ammeter        ()  ;
00023 extern  void    charge_pump_override    (parameters & a) ;   //  0 disables, !0 enables charge pump
00024 extern  void    set_v_out_opamp    (parameters & a) ;   //  0 to 1.0 sets opamp output in range 0 to 5v, charge pump permitting
00025 
00026 //bool    ee_settings_2020::wr   (char c, uint32_t i)  {           //  Write one setup char value to private buffer 'settings'
00027 /*
00028 void    slope_cmd   (struct parameters & a)   {
00029     Provides a quick way of filling lookup table.
00030     Sets percent at 3000 RPM with first parameter 0 to 100
00031 */
00032 void    slope_cmd   (struct parameters & a)   {     //  Requires two params. First %@ 3000 rpm, second slope MAX +/-20 % per krpm above
00033     const   int startat = 1800; //  rpm to start at
00034     const   int rpm_per = 200; //  rpm per lookup table step
00035     const   int threshold = startat / rpm_per;
00036     signed char    at_power_beyond, slope;
00037     pc.printf   ("Slope - set pct = %d @ 3krpm, slope %d pct above\r\n", (int32_t)a.dbl[0], (int32_t)a.dbl[1]);
00038     if  (a.numof_dbls != 2) 
00039         pc.printf   ("Need 2 params in slope, got %d, ", a.numof_dbls);
00040     else    {
00041         pc.printf   ("Got slope params %.1f, %.1f\r\n", a.dbl[0], a.dbl[1]);
00042         if  (a.dbl[0] > 100.0)  a.dbl[0] = 100.0;
00043         if  (a.dbl[0] < 0.0)    a.dbl[0] = 0.0;
00044         if  (a.dbl[1] > +20.0)  a.dbl[1] = +20.0;
00045         if  (a.dbl[1] < -20.0)  a.dbl[1] = -20.0;
00046         at_power_beyond    = (signed char)a.dbl[0];
00047         slope   = (signed char)a.dbl[1];
00048         pc.printf   ("Setting slope ");
00049         for (int i = 0; i < threshold; i++) {   //  Zero all very low speed settings
00050             user_settings.wr    (0, i);
00051         }
00052         for (int i = threshold; i < 21; i++)    {
00053             user_settings.wr    (at_power_beyond, i);
00054             pc.printf   ("%d, ", at_power_beyond);
00055             at_power_beyond += slope;
00056             if  (at_power_beyond < 0)      at_power_beyond = 0;
00057             if  (at_power_beyond > 100)    at_power_beyond = 100;
00058         }
00059         pc.printf   ("\r\nDone\r\n");
00060         user_settings.save  ();
00061         maketable   ();
00062     }
00063 }
00064 
00065 void    table_tweak_cmd   (struct parameters & a)   {     //  Requires two params. First '20', '22' etc representing hundreds RPM. Second 0 to 99 percent
00066     char    txt[100];
00067     uint32_t    d[3];
00068     txt[0] = 0;
00069     if  (a.numof_dbls != 2) 
00070         sprintf   (txt, "Need 2 params, got %d, ", a.numof_dbls);
00071     else    {
00072         d[2] = (uint32_t)a.dbl[0];
00073         d[0] = d[2] / 2;
00074         d[1] = (uint32_t)a.dbl[1];
00075         if  (d[0] > 20 || d[1] > 100 || d[2] != d[0] * 2)
00076             sprintf (txt + strlen(txt), "Param out of range %d, %d, ", d[2], d[1]);
00077         else    {
00078             pc.printf   ("Off to reset table %d RPM, %d percent\r\n", d[2] * 100, d[1]);
00079             user_settings.wr    ((char)d[1], d[0]);
00080             user_settings.save  ();
00081             maketable   ();
00082         }
00083     }
00084     if  (txt[0])
00085         pc.printf   ("Errors in table_tweak_cmd - %s\r\n", txt);
00086     else
00087         pc.printf   ("Good in table_tweak_cmd, RPM=%d, percentage=%d\r\n", d[0] * 500, d[1]);
00088 }
00089 
00090 
00091 //extern  VEXT_Data   Field;
00092 extern  FieldControl   Field;
00093 
00094 extern  int32_t set_engine_RPM_lit  (uint32_t   RPMrequest) ;   //  Returns speed error pos or neg
00095 extern  int32_t set_engine_RPM_pct  (uint32_t   RPMrequest) ;   //  Returns speed error pos or neg
00096 void    ss_cmd   (struct parameters & a)   {     //  Set engine Speed 0 - 8000 RPM
00097     uint32_t    v = (uint32_t) a.dbl[0];
00098     pc.printf   ("Setting engine RPM to %d, measured RPM returned = %d\r\n", v, set_engine_RPM_lit  (v));
00099 }
00100 
00101 void    sp_cmd   (struct parameters & a)   {     //  Set engine Speed 0 - 8000 RPM
00102     uint32_t    v = (uint32_t) a.dbl[0];
00103     pc.printf   ("Setting engine RPM percent to %d, measured RPM returned = %d\r\n", v, set_engine_RPM_pct  (v));
00104 }
00105 
00106 void    rfcmd   (struct parameters & a)   {     //  
00107 //    pc.printf   ("Field.measured_period = %u", (uint32_t)Field.get_measured_period());
00108 //    pc.printf   (", Field.measured_pw_us = %u, duty_cycle = %.3f\r\n", (uint32_t)Field.measured_pw_us, Field.duty_cycle());
00109     pc.printf   ("Field duty cycle measured = %.3f\r\n", Field.get_duty_ratio());
00110 }
00111 
00112 void    vcmd    (struct parameters & a)   {
00113     pc.printf   ("link volts %.2f, field volts %.2f\r\n", Read_Link_Volts(), Read_Field_Volts());
00114 }
00115 
00116 void    acmd    (struct parameters & a)   {
00117     pc.printf   ("amps %.2f\r\n", Read_Ammeter());
00118 }
00119 
00120 
00121 extern  void    set_pwm (double)   ;    //  Range 0.0 to 1.0
00122 void    fls_cmd (struct parameters & a)   {
00123     pc.printf   ("Setting field.limiter to %d percent\r\n", (int)a.dbl[0]);
00124     set_pwm (a.dbl[0] / 100.0);
00125 }
00126 
00127 void    set_defaults_cmd (struct parameters & a)   {
00128     struct  sldandt * p = NULL;
00129     bool    flag = true;
00130     int i = 0;
00131     while   (flag)  {
00132         p = user_settings.inform(i);    //  Returns NULL when i goes out of range
00133         if  (p == NULL)
00134             flag = false;
00135         else    {
00136             pc.printf   ("min %d, max %d, default %d, text %s\r\n", p->min, p->max, p->de_fault, p->txt);
00137             user_settings.wr    (p->de_fault, i);
00138             i++;
00139         }
00140     }
00141     user_settings.save  ();
00142 }
00143 
00144 void    servodir_cmd (struct parameters & a)   {
00145     char    ch = (char)a.dbl[0];
00146     if  (a.numof_dbls != 1 || ch > 1) {
00147         pc.printf   ("Wrong servodir set\r\n");
00148         return  ;
00149     }
00150     if  (user_settings.rd(SERVO_DIR) != ch) {
00151         pc.printf   ("Setting servo dir %.1f  \r\n", a.dbl[0]);
00152         user_settings.wr(ch, SERVO_DIR);
00153         user_settings.save();
00154     }
00155 }
00156 
00157 char * modes_txt[] =    {
00158     "0\tSafe nothing mode for cli cmd testing",
00159     "1\tPot to Servo direct, field OFF",
00160     "2\tVariable voltage",
00161     "3\tFixed voltage",
00162     "4\tEngine Revs Control",
00163     "5\tSet Engine to Driver's Pot",
00164     "6\tControl Engine by Current Load",
00165     "7\tAuto Test",
00166 }   ;
00167 
00168 int numof_op_modes = sizeof(modes_txt) / sizeof(char *);
00169 
00170 char *  get_mode_text   (uint32_t mode)  {
00171     if  (mode > numof_op_modes)   {
00172         pc.printf   ("mode OOR in get_mode_text, %d\r\n", mode);
00173         mode = numof_op_modes - 1;
00174     }
00175     return  modes_txt[mode];
00176 }
00177 
00178 void    mode20_cmd (struct parameters & a)   ;
00179 void    mode_cmd (struct parameters & a)   {
00180     if  (a.numof_dbls == 1 && (uint32_t) a.dbl[0] <= numof_op_modes)  {
00181         a.dbl[1] = a.dbl[0];
00182         a.dbl[0] = OP_MODE; //23.0;
00183         a.numof_dbls = 2;
00184         mode20_cmd  (a);
00185         return;
00186     }
00187     pc.printf   ("Current mode is %d  \r\nTo set operating mode, use mode n :- where \r\n", user_settings.rd(OP_MODE));
00188     for (int i = 0; i < numof_op_modes; i++)
00189         pc.printf   ("%s\r\n", get_mode_text(i));
00190 }
00191 
00192 void    mode20_cmd (struct parameters & a)   {
00193     struct  sldandt * p = NULL;     //  Pointer to struct containing max, min and default values, and brief text descriptor for a command
00194     int i = 0;
00195     bool    flag = true;
00196     bool    save_settings = false;
00197     int32_t    cmd_num = (int32_t) a.dbl[0], first_p = (int32_t) a.dbl[1];
00198     pc.printf   ("At user setting, numofparams = %d, dbl[0]=%.2f, dbl[1]=%.2f\r\n", a.numof_dbls, a.dbl[0], a.dbl[1]);
00199     if  (a.numof_dbls < 2)   {              //  Need at least command number followed by at least one parameter
00200         pc.printf   ("Listing Setup\r\nTo alter, enter us param number, new value\r\n");
00201         while (flag)    {
00202             p = user_settings.inform(i);    //  Returns false when i goes out of range
00203             if  (p == NULL)
00204                 flag = false;
00205             else    {
00206                 pc.printf   ("%d\tval %d, min %d, max %d, default %d, text %s\r\n", i, user_settings.rd(i), p->min, p->max, p->de_fault, p->txt);
00207                 i++;
00208             }
00209         }
00210         return  ;
00211     }       //  When too few parameters, output list. Done.
00212     p = user_settings.inform(cmd_num);  //  Set  pointer to min, max, default and text info
00213     if  (p == NULL) {
00214         pc.printf   ("Invalid command number %d in user setting entry\r\n", cmd_num);
00215         return  ;
00216     }
00217     if  (first_p < p->min || first_p > p->max)  {
00218         pc.printf   ("%s\r\nParameter min %d, max %d, you entered %d. Not setting\r\n", p->txt, p->min, p->max, first_p);
00219         return  ;
00220     }
00221     pc.printf   ("Hoping to set [%s] to %d\r\n", p->txt, first_p);
00222     switch  (cmd_num)    {
00223         case    OP_MODE:    //  
00224         case    WARM_UP_DELAY:
00225         case    WARMUP_SERVO_POS:
00226         case    SPEED_CTRL_P:
00227         case    SERVO_DIR:
00228             i = user_settings.rd(cmd_num);
00229             if  (i == first_p)
00230                 pc.printf   ("No need, [%s] already set to %d\r\n", p->txt, i);
00231             else    {
00232                 user_settings.wr((char)first_p, cmd_num);
00233                 save_settings = true;
00234                 pc.printf   ("Setting [%s] to %d\r\n", p->txt, first_p);
00235             }
00236             break;
00237         default:
00238             pc.printf   ("No code for [%s]\r\n", p->txt);
00239             break;
00240     }
00241     if  (save_settings)
00242         user_settings.save();
00243 }
00244 
00245 extern  void    auto_test_initiate  (int bulb_count)  ;
00246 void    auto_test_kickoff_cmd (struct parameters & a)   {
00247     auto_test_initiate  ((int)a.dbl[0]);
00248 }
00249 
00250 void    test_Fsfs_cmd (struct parameters & a)   {
00251     uint32_t    rpm = (uint32_t)a.dbl[0];
00252     pc.printf   ("Field.set_for_speed %d returned %d\r\n", rpm, Field.set_for_speed(rpm));
00253 }
00254 
00255 void    null_cmd (struct parameters & a)   {
00256     pc.printf   ("At null_cmd, parameters : First %.3f, second %.3f\r\n", a.dbl[0], a.dbl[1]);
00257 }
00258 
00259 void    menucmd (struct parameters & a);
00260 
00261 struct kb_command  {
00262     const char * cmd_word;         //  points to text e.g. "menu"
00263     const char * explan;
00264     void (*f)(struct parameters &);   //  points to function
00265 }  ;
00266 
00267 struct  kb_command const command_list[] = {
00268     {"?", "Lists available commands, same as ls", menucmd},
00269     {"cp", "Charge pump disable (0), enable (!0)", charge_pump_override},
00270     {"vo", "Set out volts to ESC 0 - 100 pct", set_v_out_opamp},
00271     {"ft", "Test Field.set_for_speed fn", test_Fsfs_cmd},
00272     {"at", "Initiate Auto Test sequence", auto_test_kickoff_cmd},
00273     {"svod", "Set servo sense 0 or 1", servodir_cmd},
00274     {"sd", "Set User Settings Defaults", set_defaults_cmd},
00275     {"us", "Set User Settings", mode20_cmd},
00276     {"tt", "Table Tweak 0 - 100", table_tweak_cmd},
00277     {"ss", "Set Speed 0 - 8000 RPM", ss_cmd},
00278     {"sp", "Set Speed 0 - 100 percent", sp_cmd},
00279 //    {"tl", "Throttle logger tester, enter param 0.0 - 1.0", throt_log_cmd},
00280     {"rf", "Check rise and fall on VEXT", rfcmd},
00281     {"v", "Read Battery volts", vcmd},
00282     {"i", "Read Ammeter", acmd},
00283     {"fl", "Field limiter set 0 to 99 percent", fls_cmd},
00284     {"mode", "Set operating mode - as us23", mode_cmd},
00285     {"slope", "Field limiter set pct 0 to 99 @3k, slope pct per k above", slope_cmd},
00286     {"q", "Query system - toggle message stream on/off", query_system},
00287     {"nu", "do nothing", null_cmd},
00288 };
00289 
00290 const int numof_menu_items = sizeof(command_list) / sizeof(kb_command);
00291 void    menucmd (struct parameters & a)
00292 {
00293     pc.printf("\r\nIntelligent Alternator Controller - Jon Freeman 2020\r\nAt menucmd function - listing commands:-\r\n");
00294     for(int i = 0; i < numof_menu_items; i++)
00295         pc.printf("[%s]\t\t%s\r\n", command_list[i].cmd_word, command_list[i].explan);
00296     pc.printf("End of List of Commands\r\n");
00297 }
00298 
00299 void    command_line_interpreter    ()
00300 {
00301 
00302     const int MAX_CMD_LEN = 120;
00303     static  char    cmd_line[MAX_CMD_LEN + 4];
00304     static  int     cl_index = 0;
00305     int ch;
00306     char * pEnd;
00307     static struct  parameters  param_block  ;
00308     while  (pc.readable()) {
00309         ch = tolower(pc.getc());
00310        // pc.printf("%c", ch);
00311         if  (cl_index > MAX_CMD_LEN)  {   //  trap out stupidly long command lines
00312             pc.printf   ("Error!! Stupidly long cmd line\r\n");
00313             cl_index = 0;
00314         }
00315         if  (ch == '\r' || ch >= ' ' && ch <= 'z')
00316             pc.printf("%c", ch);
00317         else    {                   //  Using <Ctrl>+ 'F', 'B' for Y, 'L', 'R' for X, 'U', 'D' for Z
00318             cl_index = 0;           //                 6    2          12   18         21   4
00319             pc.printf("[%d]", ch);
00320             //nudger  (ch); //  was used on cnc to nudge axes a tad
00321         }
00322         if(ch != '\r')  //  was this the 'Enter' key?
00323             cmd_line[cl_index++] = ch;  //  added char to command being assembled
00324         else    {   //  key was CR, may or may not be command to lookup
00325             cmd_line[cl_index] = 0; //  null terminate command string
00326             if(cl_index)    {   //  If have got some chars to lookup
00327                 int i, wrdlen;
00328                 for (i = 0; i < numof_menu_items; i++)   {   //  Look for input match in command list
00329                     wrdlen = strlen(command_list[i].cmd_word);
00330                     if(strncmp(command_list[i].cmd_word, cmd_line, wrdlen) == 0 && !isalpha(cmd_line[wrdlen]))  {   //  If match found
00331                         for (int k = 0; k < MAX_PARAMS; k++)    {
00332                             param_block.dbl[k] = 0.0;
00333                         }
00334                         param_block.position_in_list = i;
00335                         //param_block.last_time = clock    ();
00336                         param_block.numof_dbls = 0;
00337                         pEnd = cmd_line + wrdlen;
00338                         while   (*pEnd)  {          //  Assemble all numerics as doubles
00339                             param_block.dbl[param_block.numof_dbls++] = strtod    (pEnd, &pEnd);
00340                             while   (*pEnd && !isdigit(*pEnd) && '-' != *pEnd && '+' != *pEnd)  {   
00341                                 pEnd++;
00342                             }
00343                         }
00344                         pc.printf   ("\r\n");
00345 //                        for (int k = 0; k < param_block.numof_dbls; k++)
00346 //                            pc.printf   ("Read %.3f\r\n", param_block.dbl[k]);
00347 //                        param_block.times[i] = clock();
00348                         command_list[i].f(param_block);   //  execute command
00349                         i = numof_menu_items + 1;    //  to exit for loop
00350                     }   //  end of match found
00351                 }       // End of for numof_menu_items
00352                 if(i == numof_menu_items)
00353                     pc.printf("No Match Found for CMD [%s]\r\n", cmd_line);
00354             }           //  End of If have got some chars to lookup
00355             pc.printf("\r\n>");
00356             cl_index = 0;
00357         }               // End of else key was CR, may or may not be command to lookup
00358     }                   //  End of while (pc.readable())
00359 
00360 }
00361 
00362