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
cli_BLS_nortos.cpp
00001 /** 00002 * Code in this file : - 00003 * 00004 * STM3_ESC board uses two serial ports. 00005 * One (use pc.printf etc) provides 9600 baud comms to a pc or other terminal. Essential for test and setup, not used in everyday use. 00006 * 00007 * com2 provides 19200 baud comms via opto-isolators to Touch Screen Controller (see "Brute_TS_Controller_2018_11"). Opto isolation allows 00008 * for several boards to parallel up on this port, each STM3_ESC board having a unique single byte ID char in range '0' to '9'. 00009 * This enables Touch Screen controller to address ESC boards individually e.g. for requesting speed, RPM etc 00010 * while also allowing broadcast of commands not requiring responses 00011 * 00012 * Code implements a Command Line Interpreter (see class cli_2019) 00013 * Two instantiations of class cli_2019 are used, 'pcc' for pc comms and 'tsc' for touch screen comms 00014 * These read incoming commands and execute code functions accordingly. These functions are all of type 00015 * void func (struct parameters &) ; 00016 * This allows any command line parameters to pass to 'func' 00017 */ 00018 // Brushless_STM3_Ctrl_2018_11 00019 #include "mbed.h" 00020 #include "BufferedSerial.h" 00021 #include "STM3_ESC.h" 00022 #include "brushless_motor.h" 00023 00024 #include <cctype> 00025 using namespace std; 00026 00027 extern eeprom_settings user_settings ; 00028 extern error_handling_Jan_2019 ESC_Error ; // Provides array usable to store error codes. 00029 extern int WatchDog; // from main 00030 extern bool WatchDogEnable; // from main 00031 //extern bool read_temperature (float & t) ; // from main March 2020 00032 00033 extern brushless_motor MotorA, MotorB; // Controlling two motors together or individually 00034 extern const char * get_version () ; // Need this as extern const char can not be made to work. This returns & const_version_string 00035 00036 extern BufferedSerial com2, pc; // The two com ports used. There is also an unused com port, com3 setup @ 1200 baud 00037 extern void setVI_both (double v, double i) ; // Set motor voltage limit and current limit 00038 extern double Read_DriverPot (); 00039 extern double Read_BatteryVolts (); 00040 extern void mode_set_motors_both (int mode) ; // called from cli to set fw, re, rb, hb 00041 00042 // All void func (struct parameters &) ; functions addressed by command line interpreter are together below here 00043 00044 /** 00045 void ver_cmd (struct parameters & a) 00046 Responds YES, causes action NO 00047 PC or TS able to read software / firmware / hardware version string 00048 */ 00049 void ver_cmd (struct parameters & a) 00050 { 00051 if (a.source == SOURCE_PC) { 00052 pc.printf ("Version [%s]\r\n", get_version()); 00053 } 00054 else { 00055 if (a.source == SOURCE_TS) 00056 if (a.respond) { // Only respond if this board addressed 00057 a.com->printf ("%s\r", get_version()); 00058 } 00059 else 00060 pc.printf ("Crap source %d in ver_cmd\r\n", a.source); 00061 } 00062 } 00063 00064 /** 00065 void pot_cmd (struct parameters & a) 00066 Responds YES, causes action NO 00067 pc reads DriverPot. No sense in TS reading as STM3_ESC uses either/or TS, DriverPot 00068 */ 00069 void pot_cmd (struct parameters & a) 00070 { if (a.source == SOURCE_PC) 00071 pc.printf ("Driver's pot %.3f\r\n", Read_DriverPot ()); 00072 else 00073 pc.printf ("Wrong use of pot_cmd\r\n"); 00074 } 00075 00076 /** 00077 * Do nothing command, but does report board ID code '0' to '9' 00078 */ 00079 void null_cmd (struct parameters & a) 00080 { 00081 if (a.respond) 00082 a.com->printf ("Board ID %c\r\n", user_settings.rd(BOARD_ID)); 00083 } 00084 00085 00086 /** 00087 * void rdi_cmd (struct parameters & a) // read motor currents (uint32_t) and BatteryVolts (double) 00088 00089 void rdi_cmd (struct parameters & a) // read motor currents (uint32_t) and BatteryVolts (double) 00090 { // Voltage reading true volts, currents only useful as relative values 00091 if (a.respond) 00092 // a.com->printf ("rdi%d %d %.1f\r%s", MotorA.I.ave, MotorB.I.ave, Read_BatteryVolts (), a.source == SOURCE_PC ? "\n" : ""); 00093 a.com->printf ("rdi%.1f %.1f %.1f\r%s", MotorA.Idbl, MotorB.Idbl, Read_BatteryVolts (), a.source == SOURCE_PC ? "\n" : ""); 00094 // Format good to be unpicked by cli in touch screen controller 00095 } 00096 */ 00097 /** 00098 * void rvi_cmd (struct parameters & a) // read last normalised motor voltage and current values sent to pwms 00099 * 00100 */ 00101 //void rvi_cmd (struct parameters & a) // read last normalised values sent to pwms 00102 //{ 00103 // if (a.respond) 00104 // 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" : ""); 00105 //} 00106 00107 /** 00108 * void fw_cmd (struct parameters & a) // Forward command 00109 * Broadcast to all STM3_ESC boards, required to ACT but NOT respond 00110 */ 00111 void fw_cmd (struct parameters & a) // Forward command 00112 { 00113 // MotorA.set_mode (MOTOR_FORWARD); 00114 // MotorB.set_mode (MOTOR_FORWARD); 00115 mode_set_motors_both (MOTOR_FORWARD); 00116 if (a.source == SOURCE_PC) 00117 pc.printf ("fw\r\n"); // Show response to action if command from pc terminal 00118 } 00119 00120 /** 00121 * void re_cmd (struct parameters & a) // Reverse command 00122 * Broadcast to all STM3_ESC boards, required to ACT but NOT respond 00123 */ 00124 void re_cmd (struct parameters & a) // Reverse command 00125 { 00126 mode_set_motors_both (MOTOR_REVERSE); 00127 if (a.source == SOURCE_PC) 00128 pc.printf ("re\r\n"); 00129 } 00130 00131 /** 00132 * void rb_cmd (struct parameters & a) // Regen brake command 00133 * Broadcast to all STM3_ESC boards, required to ACT but NOT respond 00134 */ 00135 void rb_cmd (struct parameters & a) // Regen brake command 00136 { 00137 double tmp = a.dbl[0] / 100.0; 00138 MotorA.brake (tmp); 00139 MotorB.brake (tmp); // Corrected May 2020 - previously MotorA twice 00140 if (a.source == SOURCE_PC) 00141 pc.printf ("rb %.2f\r\n", tmp); 00142 } 00143 00144 /** 00145 * void hb_cmd (struct parameters & a) // Hand brake command 00146 * Broadcast to all STM3_ESC boards, required to ACT but NOT respond 00147 * 00148 * NOTE Jan 2019 Hand brake not implemented 00149 * May 2020 - Implemented, but not very good 00150 */ 00151 void hb_cmd (struct parameters & a) // Hand brake command 00152 { 00153 double tmp; 00154 if (a.numof_dbls != 0) tmp = a.dbl[0] / 100.0; // a.numof_dbls is int32_t 00155 else tmp = 0.33; 00156 if (a.respond) { 00157 // a.com->printf ("numof params = %d\r\n", a.numof_dbls); 00158 a.com->printf ("Hand Brake : Force 0 to 99 %.0f\r\n", tmp * 100.0); 00159 } 00160 mode_set_motors_both (MOTOR_HANDBRAKE); 00161 if (tmp < 0.0) tmp = 0.0; 00162 if (tmp > 1.0) tmp = 1.0; 00163 setVI_both (tmp / 5.0, 0.99); 00164 } 00165 00166 00167 00168 00169 /**void user_settings_cmd (struct parameters & a) // With no params, reads eeprom contents. With params sets eeprom contents 00170 * user_settings_cmd called only from pc comms. No sense calling from Touch Screen Controller 00171 * 00172 * Called without parameters - Lists to pc terminal current settings 00173 * 00174 */ 00175 void user_settings_cmd (struct parameters & a) // With no params, reads eeprom contents. With params sets eeprom contents 00176 { 00177 user_settings.edit (a.dbl, a.numof_dbls); 00178 } 00179 00180 extern struct optpar option_list[] ; //= { 00181 00182 void brake_eff_set_cmd (struct parameters & a) { // set brake effectiveness from TS May 2020 00183 char be = (char) a.dbl[0]; 00184 pc.printf ("BRAKE_EFFECTIVENESS min = %d, max = %d\r\n", option_list[BRAKE_EFFECTIVENESS].min, option_list[BRAKE_EFFECTIVENESS].max); 00185 if (be > option_list[BRAKE_EFFECTIVENESS].max) be = option_list[BRAKE_EFFECTIVENESS].max; 00186 if (be < option_list[BRAKE_EFFECTIVENESS].min) be = option_list[BRAKE_EFFECTIVENESS].min; 00187 user_settings.wr(be, BRAKE_EFFECTIVENESS); 00188 user_settings.save (); 00189 pc.printf ("Set brake effectiveness to %d pct\r\n", be); 00190 } 00191 00192 void ssl_cmd (struct parameters & a) { // set speed limit NEW and untested July 2019. Stored as speed * 10 to get 1dec place 00193 char sp = (char) (a.dbl[0] * 10.0); 00194 if (sp > option_list[TOP_SPEED].max) sp = option_list[TOP_SPEED].max; 00195 if (sp < option_list[TOP_SPEED].min) sp = option_list[TOP_SPEED].min; 00196 user_settings.wr(sp, TOP_SPEED); 00197 user_settings.save (); 00198 pc.printf ("Set speed limit to %.1f mph\r\n", a.dbl[0]); 00199 } 00200 00201 /** 00202 * void temperature_cmd (struct parameters & a) { 00203 * Few boards have temperature sensor fitted. Now only supports LM75B i2c sensor 00204 */ 00205 /*void read_temperature_cmd (struct parameters & a) { 00206 float t = -99.25; 00207 if (a.respond) { 00208 a.com->printf ("tem%c ", user_settings.rd(BOARD_ID)); 00209 if (read_temperature(t)) 00210 a.com->printf ("Temperature = %7.3f\r\n", t); 00211 else 00212 a.com->printf ("Temp sensor not fitted\r\n"); 00213 } 00214 }*/ 00215 00216 /** 00217 *void rpm_cmd (struct parameters & a) // to report e.g. RPM 1000 1000 ; speed for both motors 00218 */ 00219 void rpm_cmd (struct parameters & a) // to report e.g. RPM 1000 1000 ; speed for both motors 00220 { 00221 if (a.respond) 00222 // a.com->printf ("rpm%c %d %d\r%s", user_settings.rd(BOARD_ID), MotorA.RPM, MotorB.RPM, a.source == SOURCE_PC ? "\n" : ""); 00223 a.com->printf ("rpm%c %.0f %.0f\r%s", user_settings.rd(BOARD_ID), MotorA.dRPM, MotorB.dRPM, a.source == SOURCE_PC ? "\n" : ""); 00224 } 00225 00226 /** 00227 *void mph_cmd (struct parameters & a) // to report miles per hour 00228 */ 00229 void mph_cmd (struct parameters & a) // to report miles per hour to 1 decimal place - now 2dp May 2020 00230 { 00231 int j = 0; 00232 double speedmph = 0.0; 00233 if (MotorA.exists ()) { 00234 j |= 1; 00235 speedmph = MotorA.dMPH; 00236 } 00237 if (MotorB.exists ()) { 00238 j |= 2; 00239 speedmph += MotorB.dMPH; 00240 } 00241 if (j == 3) 00242 speedmph /= 2.0; 00243 if (a.respond) 00244 // May 17th 2020 modified line below - removed superfluous cast, upped to 2 decimal places 00245 // a.com->printf ("mph%c %.2f\r%s", user_settings.rd(BOARD_ID), speedmph, a.source == SOURCE_PC ? "\n" : ""); 00246 a.com->printf ("?s%c %.2f\r%s", user_settings.rd(BOARD_ID), speedmph, a.source == SOURCE_PC ? "\n" : ""); 00247 } 00248 00249 /** 00250 *void sysV_report (struct parameters & a) // to report system voltage 00251 * Reports system link voltage to one decimal place 00252 */ 00253 void sysV_report (struct parameters & a) // 00254 { 00255 if (a.respond) 00256 a.com->printf ("?v%c %.1f\r%s", user_settings.rd(BOARD_ID), Read_BatteryVolts(), a.source == SOURCE_PC ? "\n" : ""); 00257 } 00258 00259 /** 00260 *void sysI_report (struct parameters & a) // to report motor currents 00261 * Reports doubles for each motor current amps to 2 decimal places 00262 */ 00263 void sysI_report (struct parameters & a) // 00264 { 00265 if (a.respond) 00266 a.com->printf ("?i%c %.2f %.2f\r%s", user_settings.rd(BOARD_ID), MotorA.Idbl, MotorB.Idbl, a.source == SOURCE_PC ? "\n" : ""); 00267 } 00268 00269 /* 00270 00271 New December 2019 - possible for implementation 00272 Having implemented radio control inputs and driver pot, there is some sense in moving slider handler from touch screen controller 00273 into STM3_ESC code. 00274 New instructions to be accepted from touch screen : - 00275 {"w", "touch screen new slider touch", slider_touch_cmd}, 00276 {"x", "updated slider RANGE 0 to 99", slider_touch_position_cmd}, // max two digits 00277 {"y", "touch_screen slider finger lifted clear", slider_untouch_cmd}, 00278 */ 00279 bool finger_on_slider = false; 00280 /**void slider_touch_cmd (struct parameters & a) 00281 * 00282 * Message from touch screen controller, slider touched 00283 */ 00284 void slider_touch_cmd (struct parameters & a) { 00285 finger_on_slider = true; 00286 } 00287 00288 /**void slider_untouch_cmd (struct parameters & a) 00289 * 00290 * Message from touch screen controller, finger taken off slider 00291 */ 00292 void slider_untouch_cmd (struct parameters & a) { 00293 finger_on_slider = false; 00294 } 00295 00296 /**void slider_touch_position_cmd (struct parameters & a) 00297 * 00298 * Message from touch screen controller, latest slider touch position 00299 */ 00300 void slider_touch_position_cmd (struct parameters & a) { 00301 } 00302 00303 // End of New December 2019 00304 00305 00306 /**void vi_cmd (struct parameters & a) 00307 * 00308 * For setting motor voltage and current limits from pc terminal for test 00309 */ 00310 void vi_cmd (struct parameters & a) 00311 { 00312 setVI_both (a.dbl[0] / 100.0, a.dbl[1] / 100.0); 00313 // pc.printf ("setVI_both from %s\r\n", a.source == SOURCE_PC ? "PC" : "Touch Screen"); 00314 } 00315 00316 /** 00317 *void v_cmd (struct parameters & a) 00318 * Set motor voltage limit from either source without checking for addressed board 00319 */ 00320 void v_cmd (struct parameters & a) 00321 { 00322 MotorA.set_V_limit (a.dbl[0] / 100.0); 00323 MotorB.set_V_limit (a.dbl[0] / 100.0); 00324 } 00325 00326 /** 00327 *void i_cmd (struct parameters & a) 00328 * Set motor current limit from either source without checking for addressed board 00329 */ 00330 void i_cmd (struct parameters & a) 00331 { 00332 MotorA.set_I_limit (a.dbl[0] / 100.0); 00333 MotorB.set_I_limit (a.dbl[0] / 100.0); 00334 } 00335 00336 /** 00337 *void kd_cmd (struct parameters & a) // kick and enable the watch dog 00338 * 00339 * Brute_TS_Controller or other external controller to issue regular 'kd\r' to come here. 00340 * WatchDog disabled by default, enabled on first call to here 00341 * This is where WatchDog timer is reset and reloaded. 00342 * Timeout may be detected and handled in 8Hz loop in main programme loop 00343 */ 00344 void kd_cmd (struct parameters & a) // kick the watchdog. Reached from TS or pc. 00345 { 00346 WatchDog = WATCHDOG_RELOAD + (user_settings.rd(BOARD_ID) & 0x0f); // Reload watchdog timeout. Counted down @ 8Hz 00347 WatchDogEnable = true; // Receipt of this command sufficient to enable watchdog 00348 } 00349 00350 void wd_report (struct parameters & a) // Reachable always from pc. Only addressed board responds to TS 00351 { 00352 pc.printf ("WatchDog %d\r\n", WatchDog); 00353 } 00354 /** 00355 *void who_cmd (struct parameters & a) // Reachable always from pc. Only addressed board responds to TS 00356 * 00357 * When using STM3_ESC boards together with 'Brute Touch Screen Controller', controller needs to identify number and identity 00358 * of all connected STM3_ESC boards. To do this the Touch Screen issues '0who', '1who' ... '9who' allowing time between each 00359 * for an identified STM3_ESC to respond with 'who7' (if it was number 7) without causing contention of paralleled serial opto isolated bus 00360 */ 00361 void who_cmd (struct parameters & a) // Reachable always from pc. Only addressed board responds to TS 00362 { 00363 if (a.source == SOURCE_PC || user_settings.rd(BOARD_ID) == a.target_unit) 00364 a.com->printf ("who%c\r%s", user_settings.rd(BOARD_ID), a.source == SOURCE_PC ? "\n" : ""); 00365 } 00366 00367 extern void rcins_report () ; 00368 void qrc_cmd (struct parameters & a) // report RC1 and RC2 input condition and activity 00369 { 00370 rcins_report (); 00371 } 00372 00373 /** 00374 *void rcin_pccmd (struct parameters & a) 00375 * 00376 * For test, reports to pc terminal info about radio control input channels 00377 */ 00378 //void rcin_pccmd (struct parameters & a) 00379 //{ 00380 // rcin_report (); 00381 //} 00382 /* 00383 void scmd (struct parameters & a) // filter coefficient fiddler 00384 { 00385 switch ((int)a.dbl[0]) { 00386 case 1: 00387 MotorA.sdbl[1] = MotorB.sdbl[1] = a.dbl[1]; 00388 break; 00389 case 2: 00390 MotorA.sdbl[2] = MotorB.sdbl[2] = a.dbl[1]; 00391 break; 00392 case 3: 00393 MotorA.sdbl[3] = MotorB.sdbl[3] = a.dbl[1]; 00394 break; 00395 case 4: 00396 MotorA.sdbl[4] = MotorB.sdbl[4] = a.dbl[1]; 00397 break; 00398 default: 00399 pc.printf ("Wrong use of scmd %f\r\n", a.dbl[0]); 00400 } 00401 pc.printf ("Filter Coefficient Fiddler - used in brushless_motor::speed_monitor_and_control ()"); 00402 pc.printf ("Filter Coeffs 1 to 4\r\n"); 00403 pc.printf ("1 %.3f\tPscale 0.01-0.5\r\n", MotorA.sdbl[1]); 00404 pc.printf ("2 %.3f\tP_gain 1.0-1000.0\r\n", MotorA.sdbl[2]); 00405 pc.printf ("3 %.3f\tDscale 0.01-0.5\r\n", MotorA.sdbl[3]); 00406 pc.printf ("4 %.3f\tD_gain 1.0-1000.0\r\n", MotorA.sdbl[4]); 00407 // pc.printf ("5 Set target_speed\r\n"); 00408 } 00409 */ 00410 struct kb_command { // Commands tabulated as list of these structures as seen below 00411 const char * cmd_word; // points to text e.g. "menu" 00412 const char * explan; // very brief explanation or clue as to purpose of function 00413 void (*f)(struct parameters &); // points to function 00414 } ; // Positioned in code here as knowledge needed by following menucmd 00415 00416 /** 00417 * void menucmd (struct parameters & a) 00418 * 00419 * List available terminal commands to pc terminal. No sense in touch screen using this 00420 */ 00421 void menucmd (struct parameters & a) 00422 { 00423 if (a.respond) { 00424 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"); 00425 for(int i = 0; i < a.numof_menu_items; i++) 00426 a.com->printf("[%s]\t\t%s\r\n", a.command_list[i].cmd_word, a.command_list[i].explan); 00427 a.com->printf("End of List of Commands\r\n"); 00428 } 00429 } 00430 00431 /********************** END OF COMMAND LINE INTERPRETER COMMANDS *************************************/ 00432 00433 00434 /** 00435 * struct kb_command const loco_command_list[] = { 00436 * List of commands accepted from external controller through opto isolated com port 19200, 8,n,1 00437 */ 00438 struct kb_command const loco_command_list[] = { // For comms between STM3_ESC and 'Brute Touch Screen Controller' 00439 // ***** Broadcast commands for all STM3_ESC boards to execute. Boards NOT to send serial response ***** 00440 {"fw", "forward", fw_cmd}, 00441 {"re", "reverse", re_cmd}, 00442 {"rb", "regen brake 0 to 99 %", rb_cmd}, // max two digits 00443 {"hb", "hand brake", hb_cmd}, 00444 {"v", "set motors V percent RANGE 0 to 99", v_cmd}, 00445 {"i", "set motors I percent RANGE 0 to 99", i_cmd}, 00446 {"vi", "set motors V and I percent RANGE 0 to 99", vi_cmd}, 00447 {"w", "touch screen new slider touch", slider_touch_cmd}, 00448 {"x", "updated slider RANGE 0 to 99", slider_touch_position_cmd}, 00449 {"y", "touch_screen slider finger lifted clear", slider_untouch_cmd}, 00450 {"kd", "kick the dog, reloads WatchDog", kd_cmd}, 00451 {"ssl", "set speed limit e.g. 10.7", ssl_cmd}, // NEW July 2019 00452 {"sbe", "set brake effectiveness 5 to 90 percent", brake_eff_set_cmd}, // NEW May 2020 00453 // ***** Endof Broadcast commands for all STM3_ESC boards to execute. Boards NOT to send serial response ***** 00454 00455 // ***** Following are rx'd requests for serial response from addressed STM3_ESC only 00456 {"?v", "Report system bus voltage", sysV_report}, 00457 {"?i", "Report motor both currents", sysI_report}, 00458 {"who", "search for connected units, e.g. 3who returs 'who3' if found", who_cmd}, 00459 // {"tem", "report temperature", read_temperature_cmd}, 00460 {"mph", "read loco speed miles per hour", mph_cmd}, 00461 {"?s", "read loco speed miles per hour", mph_cmd}, // Shorter-hand added 17th May 2020 00462 // {"ssl", "set speed limit e.g. 10.7", ssl_cmd}, // NEW July 2019 00463 // {"sbe", "set brake effectiveness 5 to 90 percent", brake_eff_set_cmd}, // NEW May 2020 00464 // {"rvi", "read most recent values sent to pwms", rvi_cmd}, 00465 // {"rdi", "read motor currents and power voltage", rdi_cmd}, 00466 // ***** Endof 00467 } ; 00468 00469 00470 /** 00471 struct kb_command const loco_command_list[] = { 00472 List of commands accepted from external pc through non-opto isolated com port 9600, 8,n,1 00473 */ 00474 struct kb_command const pc_command_list[] = { 00475 {"ls", "Lists available commands", menucmd}, 00476 {"?", "Lists available commands, same as ls", menucmd}, 00477 {"pot", "read drivers control pot", pot_cmd}, 00478 {"fw", "forward", fw_cmd}, 00479 {"re", "reverse", re_cmd}, 00480 {"rb", "regen brake 0 to 99 %", rb_cmd}, 00481 {"hb", "hand brake", hb_cmd}, 00482 {"v", "set motors V percent RANGE 0 to 100", v_cmd}, 00483 {"i", "set motors I percent RANGE 0 to 100", i_cmd}, 00484 {"vi", "set motors V and I percent RANGE 0 to 100", vi_cmd}, 00485 {"?v", "Report system bus voltage", sysV_report}, 00486 {"?i", "Report motor both currents", sysI_report}, 00487 {"?w", "show WatchDog timer contents", wd_report}, 00488 {"kd", "kick the dog, reloads WatchDog", kd_cmd}, 00489 {"who", "search for connected units, e.g. 3who returs 'who3' if found", who_cmd}, 00490 {"us", "read or set user settings in eeprom", user_settings_cmd}, // Big change Jan 2019 00491 {"ssl", "set speed limit e.g. 10.7", ssl_cmd}, // NEW July 2019 ONLY HERE FOR TEST, normal use is from Touch Screen only. 00492 {"sbe", "set brake effectiveness 5 to 90 percent", brake_eff_set_cmd}, // NEW May 2020 00493 // {"erase", "set eeprom contents to all 0xff", erase_cmd}, 00494 // {"tem", "report temperature", read_temperature_cmd}, // Reports -50 when sensor not fitted 00495 {"ver", "Version", ver_cmd}, 00496 {"rpm", "read motor pair speeds", rpm_cmd}, 00497 // {"mph", "read loco speed miles per hour", mph_cmd}, 00498 {"?s", "read loco speed miles per hour", mph_cmd}, 00499 {"?rc", "report RC1 and RC2 input condition and activity", qrc_cmd}, 00500 // {"rvi", "read most recent values sent to pwms", rvi_cmd}, 00501 // {"rdi", "read motor currents and power voltage", rdi_cmd}, 00502 // {"bc", "bogie constants - wheel dia, motor pinion, wheel gear", bogie_constants_report_cmd}, 00503 // {"gbb", "get bogie bytes from eeprom and report", gbb_cmd}, // OBSOLETE, replaced by 'gbb' 00504 {"nu", "do nothing", null_cmd}, 00505 } ; 00506 00507 // cli_2019 (BufferedSerial * comport, kb_command const * list, int list_len, int source) { 00508 /** 00509 * cli_2019 pcc (&pc, pc_command_list, sizeof(pc_command_list) / sizeof(kb_command), SOURCE_PC) ; 00510 * cli_2019 tsc (&com2, loco_command_list, sizeof(loco_command_list) / sizeof(kb_command), SOURCE_TS) ; 00511 * 00512 * Instantiate two Command Line Interpreters, one for pc terminal and one for touch screen controller 00513 */ 00514 cli_2019 pcc (&pc, pc_command_list, sizeof(pc_command_list) / sizeof(kb_command), SOURCE_PC) ; 00515 cli_2019 tsc (&com2, loco_command_list, sizeof(loco_command_list) / sizeof(kb_command), SOURCE_TS) ; 00516 00517 /* 00518 New - March 2018 00519 Using opto isolated serial port, paralleled up using same pair to multiple STM3_ESC boards running this code. 00520 New feature - commands have optional prefix digit 0-9 indicating which unit message is addressed to. 00521 Commands without prefix digit - broadcast to all units, all to obey but none to respond. 00522 Only units recognising its address from prefix digit may respond. This avoids bus contention. 00523 But for BROADCAST commands, '0' may respond on behalf of the group 00524 */ 00525 00526 /** 00527 * void cli_2019::test () { 00528 * 00529 * Daft check that class instantiation worked 00530 */ 00531 void cli_2019::flush () { 00532 // char ch; 00533 while (a.com->readable()) 00534 a.com->getc(); 00535 //pc.printf ("At cli2019::test, source %d len %d,\r\n", a.source, a.numof_menu_items); 00536 } 00537 00538 /** 00539 * void cli_2019::core () { 00540 * 00541 * Command Line Interpreter. 00542 * This to be called every few milli secs from main programme loop. 00543 * Reads any rx'd chars into command line buffer, returns when serial buffer empty. 00544 * If last char rx'd war '\r' end of text delimiter, apt command_list is searched for a matched command in command line 00545 * If matched command found, apt function is executed. 00546 * Parameters available to functions from 'parameters' struct. 00547 */ 00548 void cli_2019::core () { 00549 int ch, IAm = user_settings.rd(BOARD_ID); 00550 char * pEnd;//, * cmd_line_ptr; 00551 while (a.com->readable()) { 00552 ch = a.com->getc(); 00553 if (clindex > MAX_CMD_LEN) { // trap out stupidly long command lines 00554 ESC_Error.set (FAULT_COM_LINE_LEN, 1); // Set FAULT_EEPROM bit 0 if 24LC64 problem 00555 a.com->printf ("Error!! Stupidly long cmd line\r\n"); 00556 clindex = 0; 00557 } 00558 if(ch != '\r') { // was this the 'Enter' key? 00559 if (ch != '\n') // Ignore line feeds 00560 cmdline[clindex++] = ch; // added char to command being assembled 00561 } 00562 else { // key was CR, may or may not be command to lookup 00563 a.target_unit = BROADCAST; // Set to BROADCAST default once found command line '\r' 00564 cmdline_ptr = cmdline; 00565 cmdline[clindex] = 0; // null terminate command string 00566 if(clindex) { // If have got some chars to lookup 00567 int i, wrdlen; 00568 if (isdigit(cmdline[0])) { // Look for command with prefix digit 00569 cmdline_ptr++; // point past identified digit prefix 00570 a.target_unit = cmdline[0]; // '0' to '9' 00571 //com->printf ("Got prefix %c\r\n", cmd_line[0]); 00572 } 00573 for (i = 0; i < a.numof_menu_items; i++) { // Look for input match in command list 00574 wrdlen = strlen(commandlist[i].cmd_word); 00575 if(strncmp(commandlist[i].cmd_word, cmdline_ptr, wrdlen) == 0 && !isalpha(cmdline_ptr[wrdlen])) { // If match found 00576 for (int k = 0; k < MAX_CLI_PARAMS; k++) { 00577 a.dbl[k] = 0.0; 00578 } 00579 a.position_in_list = i; 00580 a.numof_dbls = 0; 00581 // pEnd = cmdline + clindex; // does indeed point to null terminator 00582 pEnd = cmdline_ptr + wrdlen; 00583 // while (*pEnd) { // Assemble all numerics as doubles 00584 while (*pEnd && a.numof_dbls < MAX_CLI_PARAMS) { // Assemble all numerics as doubles 00585 a.dbl[a.numof_dbls++] = strtod (pEnd, &pEnd); 00586 while (*pEnd && (pEnd < cmdline + clindex) && *pEnd && !isdigit(*pEnd) && ('.' != *pEnd) && ('-' != *pEnd) && ('+' != *pEnd)) { // Can crash cli here with e.g. 'ls -l' 00587 pEnd++; 00588 } // problem occurs with input such as "- ", or "-a", seemingly anything dodgy following a '-' or a '+' 00589 if (((*pEnd == '-') || (*pEnd == '+')) &&(!isdigit(*(pEnd+1))) && ('.' !=*(pEnd+1))) 00590 pEnd = cmdline + clindex; // fixed by aborting remainder of line 00591 } 00592 a.respond = a.resp_always; 00593 if (((a.target_unit == BROADCAST) && (IAm == '0')) || (IAm == a.target_unit)) 00594 a.respond = true; // sorted 26/4/18 00595 // All boards to obey BROADCAST command, only specific board to obey number prefixed command 00596 if ((a.target_unit == BROADCAST) || (IAm == a.target_unit)) 00597 commandlist[i].f(a); // execute command if addressed to this unit 00598 i = a.numof_menu_items + 1; // to exit for loop 00599 } // end of match found 00600 } // End of for numof_menu_items 00601 if(i == a.numof_menu_items) { 00602 // a.com->printf("No Match Found for CMD [%s]\r\n", cmdline); 00603 pc.printf("No Match Found for CMD [%s]\r\n", cmdline); 00604 ESC_Error.set (FAULT_COM_LINE_NOMATCH, 1); // Set FAULT_EEPROM bit 0 if 24LC64 problem 00605 } 00606 } // End of If have got some chars to lookup 00607 clindex = 0; 00608 } // End of else key was CR, may or may not be command to lookup 00609 } // End of while (com->readable()) 00610 } // end of command line interpreter core function 00611 00612
Generated on Tue Jul 19 2022 12:28:36 by 1.7.2