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
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
Generated on Fri Jul 22 2022 15:22:19 by 1.7.2