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

Committer:
JonFreeman
Date:
Tue Jan 15 09:03:57 2019 +0000
Revision:
10:e40d8724268a
Parent:
9:ac2412df01be
Child:
11:bfb73f083009
Buggered serial comms to TS controller

Who changed what in which revision?

UserRevisionLine numberNew contents of line
JonFreeman 9:ac2412df01be 1 // DualBLS2018_06
JonFreeman 6:f289a49c1eae 2 #include "mbed.h"
JonFreeman 6:f289a49c1eae 3 #include "BufferedSerial.h"
JonFreeman 6:f289a49c1eae 4
JonFreeman 6:f289a49c1eae 5 #include <cctype>
JonFreeman 6:f289a49c1eae 6 #include "DualBLS.h"
JonFreeman 6:f289a49c1eae 7 using namespace std;
JonFreeman 6:f289a49c1eae 8
JonFreeman 6:f289a49c1eae 9 extern int I_Am () ; // Returns boards id number as ASCII char '0', '1' etc. Code for Broadcast = '\r'
JonFreeman 8:93203f473f6e 10 extern int WatchDog;
JonFreeman 8:93203f473f6e 11 extern bool WatchDogEnable;
JonFreeman 8:93203f473f6e 12 extern char mode_bytes[];
JonFreeman 6:f289a49c1eae 13
JonFreeman 6:f289a49c1eae 14 const int BROADCAST = '\r';
JonFreeman 6:f289a49c1eae 15 const int MAX_PARAMS = 20;
JonFreeman 6:f289a49c1eae 16 struct parameters {
JonFreeman 7:6deaeace9a3e 17 struct kb_command const * command_list;
JonFreeman 7:6deaeace9a3e 18 BufferedSerial * com; // pc or com2
JonFreeman 7:6deaeace9a3e 19 char cmd_line[120];
JonFreeman 7:6deaeace9a3e 20 char * cmd_line_ptr;
JonFreeman 7:6deaeace9a3e 21 int32_t position_in_list, numof_dbls, target_unit, numof_menu_items, cl_index, gp_i;
JonFreeman 6:f289a49c1eae 22 double dbl[MAX_PARAMS];
JonFreeman 7:6deaeace9a3e 23 bool respond, resp_always;
JonFreeman 6:f289a49c1eae 24 } ;
JonFreeman 6:f289a49c1eae 25
JonFreeman 7:6deaeace9a3e 26 struct parameters pccom, lococom;
JonFreeman 6:f289a49c1eae 27 // WithOUT RTOS
JonFreeman 6:f289a49c1eae 28 extern BufferedSerial com2, pc;
JonFreeman 6:f289a49c1eae 29 extern void send_test () ;
JonFreeman 6:f289a49c1eae 30 extern void setVI (double v, double i) ;
JonFreeman 6:f289a49c1eae 31 extern void setV (double v) ;
JonFreeman 6:f289a49c1eae 32 extern void setI (double i) ;
JonFreeman 6:f289a49c1eae 33 extern void read_last_VI (double * val) ; // only for test from cli
JonFreeman 6:f289a49c1eae 34
JonFreeman 7:6deaeace9a3e 35 //BufferedSerial * com;
JonFreeman 8:93203f473f6e 36 extern double Read_DriverPot ();
JonFreeman 8:93203f473f6e 37 void pot_cmd (struct parameters & a)
JonFreeman 8:93203f473f6e 38 {
JonFreeman 8:93203f473f6e 39 pc.printf ("Driver's pot %.3f\r\n", Read_DriverPot ());
JonFreeman 8:93203f473f6e 40 }
JonFreeman 6:f289a49c1eae 41
JonFreeman 6:f289a49c1eae 42 void null_cmd (struct parameters & a)
JonFreeman 6:f289a49c1eae 43 {
JonFreeman 6:f289a49c1eae 44 if (a.respond)
JonFreeman 7:6deaeace9a3e 45 a.com->printf ("At null_cmd, board ID %c, parameters : First %.3f, second %.3f\r\n", I_Am(), a.dbl[0], a.dbl[1]);
JonFreeman 6:f289a49c1eae 46 }
JonFreeman 6:f289a49c1eae 47
JonFreeman 8:93203f473f6e 48 // {"wden", "enable watchdog if modes allow", wden_lococmd},
JonFreeman 8:93203f473f6e 49 // {"wddi", "disable watchdog always", wddi_lococmd},
JonFreeman 8:93203f473f6e 50
JonFreeman 8:93203f473f6e 51 void wden_lococmd (struct parameters & a)
JonFreeman 8:93203f473f6e 52 {
JonFreeman 8:93203f473f6e 53 if (mode_bytes[COMM_SRC] != 3) // When not hand pot control, allow watchdog enable
JonFreeman 8:93203f473f6e 54 WatchDogEnable = true;
JonFreeman 8:93203f473f6e 55 }
JonFreeman 8:93203f473f6e 56 void wden_pccmd (struct parameters & a)
JonFreeman 8:93203f473f6e 57 {
JonFreeman 8:93203f473f6e 58 wden_lococmd (a);
JonFreeman 8:93203f473f6e 59 a.com->printf ("Watchdog %sabled\r\n", WatchDogEnable ? "En":"Dis");
JonFreeman 8:93203f473f6e 60 }
JonFreeman 8:93203f473f6e 61
JonFreeman 8:93203f473f6e 62 void wddi_lococmd (struct parameters & a)
JonFreeman 8:93203f473f6e 63 {
JonFreeman 8:93203f473f6e 64 WatchDogEnable = false;
JonFreeman 8:93203f473f6e 65 }
JonFreeman 8:93203f473f6e 66 void wddi_pccmd (struct parameters & a)
JonFreeman 8:93203f473f6e 67 {
JonFreeman 8:93203f473f6e 68 wddi_lococmd (a);
JonFreeman 8:93203f473f6e 69 a.com->printf ("Watchdog %sabled\r\n", WatchDogEnable ? "En":"Dis");
JonFreeman 8:93203f473f6e 70 }
JonFreeman 8:93203f473f6e 71
JonFreeman 8:93203f473f6e 72 extern void prscfuck (int);
JonFreeman 8:93203f473f6e 73 void pf_cmd (struct parameters & a)
JonFreeman 8:93203f473f6e 74 {
JonFreeman 8:93203f473f6e 75 prscfuck ((int)a.dbl[0]);
JonFreeman 8:93203f473f6e 76 }
JonFreeman 8:93203f473f6e 77
JonFreeman 8:93203f473f6e 78 extern void report_motor_types () ;
JonFreeman 8:93203f473f6e 79 void mt_cmd (struct parameters & a)
JonFreeman 8:93203f473f6e 80 {
JonFreeman 8:93203f473f6e 81 report_motor_types ();
JonFreeman 8:93203f473f6e 82 // if (a.respond)
JonFreeman 8:93203f473f6e 83 // a.com->printf ("At null_cmd, board ID %c, parameters : First %.3f, second %.3f\r\n", I_Am(), a.dbl[0], a.dbl[1]);
JonFreeman 8:93203f473f6e 84 }
JonFreeman 8:93203f473f6e 85
JonFreeman 8:93203f473f6e 86 extern void mode_set_both_motors (int mode, double val) ; // called from cli to set fw, re, rb, hb
JonFreeman 6:f289a49c1eae 87 extern void read_supply_vi (double * val) ;
JonFreeman 6:f289a49c1eae 88
JonFreeman 6:f289a49c1eae 89 void rdi_cmd (struct parameters & a) // read motor currents
JonFreeman 6:f289a49c1eae 90 {
JonFreeman 6:f289a49c1eae 91 if (a.respond) {
JonFreeman 6:f289a49c1eae 92 double r[4];
JonFreeman 6:f289a49c1eae 93 read_supply_vi (r); // get MotorA.I.ave, MotorB.I.ave, Battery volts
JonFreeman 7:6deaeace9a3e 94 a.com->printf ("rdi%.0f %.0f %.1f\r", r[0], r[1], r[2]); // Format good to be unpicked by cli in touch screen controller
JonFreeman 6:f289a49c1eae 95 }
JonFreeman 6:f289a49c1eae 96 }
JonFreeman 6:f289a49c1eae 97
JonFreeman 6:f289a49c1eae 98 void rvi_cmd (struct parameters & a) // read last normalised values sent to pwms
JonFreeman 6:f289a49c1eae 99 {
JonFreeman 6:f289a49c1eae 100 if (a.respond) {
JonFreeman 6:f289a49c1eae 101 double r[6];
JonFreeman 6:f289a49c1eae 102 read_last_VI (r);
JonFreeman 7:6deaeace9a3e 103 a.com->printf ("rvi%.2f %.2f %.2f %.2f\r", r[0], r[1], r[2], r[3]);
JonFreeman 6:f289a49c1eae 104 }
JonFreeman 6:f289a49c1eae 105 }
JonFreeman 6:f289a49c1eae 106
JonFreeman 6:f289a49c1eae 107 void fw_cmd (struct parameters & a) // Forward command
JonFreeman 6:f289a49c1eae 108 {
JonFreeman 8:93203f473f6e 109 mode_set_both_motors (FORWARD, 0.0);
JonFreeman 6:f289a49c1eae 110 }
JonFreeman 6:f289a49c1eae 111
JonFreeman 6:f289a49c1eae 112 void re_cmd (struct parameters & a) // Reverse command
JonFreeman 6:f289a49c1eae 113 {
JonFreeman 8:93203f473f6e 114 mode_set_both_motors (REVERSE, 0.0);
JonFreeman 6:f289a49c1eae 115 }
JonFreeman 6:f289a49c1eae 116
JonFreeman 6:f289a49c1eae 117 void rb_cmd (struct parameters & a) // Regen brake command
JonFreeman 6:f289a49c1eae 118 {
JonFreeman 6:f289a49c1eae 119 double b = a.dbl[0] / 100.0;
JonFreeman 7:6deaeace9a3e 120 // a.com->printf ("Applying brake %.3f\r\n", b);
JonFreeman 8:93203f473f6e 121 mode_set_both_motors (REGENBRAKE, b);
JonFreeman 6:f289a49c1eae 122 // apply_brake (b);
JonFreeman 6:f289a49c1eae 123 }
JonFreeman 6:f289a49c1eae 124
JonFreeman 6:f289a49c1eae 125 extern bool wr_24LC64 (int mem_start_addr, char * source, int length) ;
JonFreeman 6:f289a49c1eae 126 extern bool rd_24LC64 (int mem_start_addr, char * dest, int length) ;
JonFreeman 6:f289a49c1eae 127
JonFreeman 6:f289a49c1eae 128 void erase_cmd (struct parameters & a) // Sets eeprom contents to all 0xff. 256 pages of 32 bytes to do
JonFreeman 6:f289a49c1eae 129 {
JonFreeman 6:f289a49c1eae 130 char t[36];
JonFreeman 6:f289a49c1eae 131 for (int i = 0; i < 32; i++)
JonFreeman 6:f289a49c1eae 132 t[i] = 0xff;
JonFreeman 6:f289a49c1eae 133 for (int i = 0; i < 8191; i += 32) {
JonFreeman 7:6deaeace9a3e 134 a.com->printf (".");
JonFreeman 6:f289a49c1eae 135 if (!wr_24LC64 (i, t, 32))
JonFreeman 7:6deaeace9a3e 136 a.com->printf ("eeprom write prob\r\n");
JonFreeman 6:f289a49c1eae 137 }
JonFreeman 6:f289a49c1eae 138 }
JonFreeman 6:f289a49c1eae 139 /*struct motorpairoptions { // This to be user settable in eeprom, 32 bytes
JonFreeman 6:f289a49c1eae 140 uint8_t MotA_dir, // 0 or 1
JonFreeman 6:f289a49c1eae 141 MotB_dir, // 0 or 1
JonFreeman 6:f289a49c1eae 142 gang, // 0 for separate control (robot mode), 1 for ganged loco bogie mode
JonFreeman 6:f289a49c1eae 143 serv1, // 0, 1, 2 = Not used, Input, Output
JonFreeman 6:f289a49c1eae 144 serv2, // 0, 1, 2 = Not used, Input, Output
JonFreeman 6:f289a49c1eae 145 cmd_source, // 0 Invalid, 1 COM1, 2 COM2, 3 Pot, 4 Servo1, 5 Servo2
JonFreeman 6:f289a49c1eae 146 {'1', '9', '0', "Alternative ID ascii '1' to '9'"}, // defaults to '0' before eerom setup for first time
JonFreeman 6:f289a49c1eae 147 {50, 250, 98, "Wheel diameter mm"}, // New 01/06/2018
JonFreeman 6:f289a49c1eae 148 {10, 250, 27, "Motor pinion"}, // New 01/06/2018
JonFreeman 6:f289a49c1eae 149 {50, 250, 85, "Wheel gear"}, // New 01/06/2018
JonFreeman 6:f289a49c1eae 150 // last;
JonFreeman 6:f289a49c1eae 151 } ;
JonFreeman 6:f289a49c1eae 152 */
JonFreeman 8:93203f473f6e 153
JonFreeman 8:93203f473f6e 154 // New 22 June 2018
JonFreeman 8:93203f473f6e 155 // get bogie bytes - report back to touch controller
JonFreeman 8:93203f473f6e 156 void gbb_cmd (struct parameters & a) //
JonFreeman 8:93203f473f6e 157 {
JonFreeman 8:93203f473f6e 158 if (a.target_unit == BROADCAST || !a.resp_always) {
JonFreeman 8:93203f473f6e 159 // a.com->printf ("At mode_cmd, can not use BROADCAST with mode_cmd\r\n");
JonFreeman 8:93203f473f6e 160 } else {
JonFreeman 8:93203f473f6e 161 pc.printf ("At gbb\r\n");
JonFreeman 8:93203f473f6e 162 char eeprom_contents[36]; // might need to be unsigned?
JonFreeman 8:93203f473f6e 163 memset (eeprom_contents, 0, 36);
JonFreeman 8:93203f473f6e 164 a.com->printf ("gbb");
JonFreeman 8:93203f473f6e 165 rd_24LC64 (0, eeprom_contents, 32);
JonFreeman 8:93203f473f6e 166 for (int i = 0; i < numof_eeprom_options; i++)
JonFreeman 8:93203f473f6e 167 a.com->printf (" %d", eeprom_contents[i]);
JonFreeman 8:93203f473f6e 168 a.com->putc ('\r');
JonFreeman 8:93203f473f6e 169 a.com->putc ('\n');
JonFreeman 8:93203f473f6e 170 }
JonFreeman 8:93203f473f6e 171 }
JonFreeman 6:f289a49c1eae 172
JonFreeman 6:f289a49c1eae 173 void mode_cmd (struct parameters & a) // With no params, reads eeprom contents. With params sets eeprom contents
JonFreeman 6:f289a49c1eae 174 {
JonFreeman 7:6deaeace9a3e 175 if (a.target_unit == BROADCAST || !a.resp_always) {
JonFreeman 7:6deaeace9a3e 176 // a.com->printf ("At mode_cmd, can not use BROADCAST with mode_cmd\r\n");
JonFreeman 6:f289a49c1eae 177 } else {
JonFreeman 6:f289a49c1eae 178 char t[36];
JonFreeman 7:6deaeace9a3e 179 a.com->printf ("At mode_cmd with node %d\r\n", a.target_unit);
JonFreeman 6:f289a49c1eae 180 rd_24LC64 (0, t, 32);
JonFreeman 7:6deaeace9a3e 181 a.com->printf ("Numof params=%d\r\n", a.numof_dbls);
JonFreeman 6:f289a49c1eae 182 for (int i = 0; i < numof_eeprom_options; i++)
JonFreeman 7:6deaeace9a3e 183 a.com->printf ("%2x\t%s\r\n", t[i], option_list[i].t);
JonFreeman 6:f289a49c1eae 184 if (a.numof_dbls == 0) { // Read present contents, do not write
JonFreeman 7:6deaeace9a3e 185 a.com->printf ("That's it\r\n");
JonFreeman 6:f289a49c1eae 186 } else { // Write new shit to eeprom
JonFreeman 7:6deaeace9a3e 187 a.com->printf ("\r\n");
JonFreeman 6:f289a49c1eae 188 if (a.numof_dbls != numof_eeprom_options) {
JonFreeman 7:6deaeace9a3e 189 a.com->printf ("params required = %d, you offered %d\r\n", numof_eeprom_options, a.numof_dbls);
JonFreeman 6:f289a49c1eae 190 } else { // Have been passed correct number of parameters
JonFreeman 6:f289a49c1eae 191 int b;
JonFreeman 7:6deaeace9a3e 192 a.com->printf("Ready to write params to eeprom\r\n");
JonFreeman 6:f289a49c1eae 193 for (int i = 0; i < numof_eeprom_options; i++) {
JonFreeman 6:f289a49c1eae 194 b = (int)a.dbl[i]; // parameter value to check against limits
JonFreeman 6:f289a49c1eae 195 if (i == 6) // Alternative ID must be turned to ascii
JonFreeman 6:f289a49c1eae 196 b |= '0';
JonFreeman 6:f289a49c1eae 197 if ((b < option_list[i].min) || (b > option_list[i].max)) { // if parameter out of range
JonFreeman 7:6deaeace9a3e 198 a.com->printf("Warning - Parameter = %d, out of range, setting to default %d\r\n", b, option_list[i].def);
JonFreeman 6:f289a49c1eae 199 b = option_list[i].def;
JonFreeman 6:f289a49c1eae 200 }
JonFreeman 7:6deaeace9a3e 201 a.com->printf ("0x%2x\t%s\r\n", (t[i] = b), option_list[i].t);
JonFreeman 6:f289a49c1eae 202 }
JonFreeman 6:f289a49c1eae 203 wr_24LC64 (0, t, numof_eeprom_options);
JonFreeman 6:f289a49c1eae 204 memcpy (mode_bytes,t,32);
JonFreeman 7:6deaeace9a3e 205 a.com->printf("Parameters set in eeprom\r\n");
JonFreeman 6:f289a49c1eae 206 }
JonFreeman 6:f289a49c1eae 207 }
JonFreeman 6:f289a49c1eae 208 }
JonFreeman 6:f289a49c1eae 209 }
JonFreeman 6:f289a49c1eae 210 /*void coast_cmd (struct parameters & a) { // Coast
JonFreeman 6:f289a49c1eae 211
JonFreeman 6:f289a49c1eae 212 }
JonFreeman 6:f289a49c1eae 213 */
JonFreeman 6:f289a49c1eae 214 void hb_cmd (struct parameters & a)
JonFreeman 6:f289a49c1eae 215 {
JonFreeman 6:f289a49c1eae 216 if (a.respond) {
JonFreeman 7:6deaeace9a3e 217 a.com->printf ("numof params = %d\r\n", a.numof_dbls);
JonFreeman 7:6deaeace9a3e 218 a.com->printf ("Hand Brake : First %.3f, second %.3f\r\n", a.dbl[0], a.dbl[1]);
JonFreeman 6:f289a49c1eae 219 }
JonFreeman 8:93203f473f6e 220 mode_set_both_motors (HANDBRAKE, 0.0);
JonFreeman 6:f289a49c1eae 221 }
JonFreeman 6:f289a49c1eae 222
JonFreeman 6:f289a49c1eae 223 extern uint32_t last_temp_count;
JonFreeman 6:f289a49c1eae 224 void temperature_cmd (struct parameters & a) {
JonFreeman 6:f289a49c1eae 225 if (a.respond) {
JonFreeman 7:6deaeace9a3e 226 a.com->printf ("tem%c %d\r\n", mode_bytes[ID], (last_temp_count / 16) - 50);
JonFreeman 6:f289a49c1eae 227 }
JonFreeman 6:f289a49c1eae 228 }
JonFreeman 6:f289a49c1eae 229
JonFreeman 6:f289a49c1eae 230 void bogie_constants_report_cmd (struct parameters & a) {
JonFreeman 6:f289a49c1eae 231 if (a.respond) {
JonFreeman 7:6deaeace9a3e 232 a.com->printf ("bc%c %d %d %d\r\n", mode_bytes[ID], mode_bytes[WHEELDIA], mode_bytes[MOTPIN], mode_bytes[WHEELGEAR]);
JonFreeman 6:f289a49c1eae 233 }
JonFreeman 6:f289a49c1eae 234 }
JonFreeman 6:f289a49c1eae 235
JonFreeman 6:f289a49c1eae 236 extern void read_RPM (uint32_t * dest) ;
JonFreeman 6:f289a49c1eae 237 void rpm_cmd (struct parameters & a) // to report e.g. RPM 1000 1000 ; speed for both motors
JonFreeman 6:f289a49c1eae 238 {
JonFreeman 6:f289a49c1eae 239 if (a.respond) {
JonFreeman 6:f289a49c1eae 240 uint32_t dest[3];
JonFreeman 7:6deaeace9a3e 241 read_RPM (dest); // gets rpm for each motor
JonFreeman 7:6deaeace9a3e 242 a.com->printf ("rpm%d %d\r", dest[0], dest[1]);
JonFreeman 6:f289a49c1eae 243 }
JonFreeman 6:f289a49c1eae 244 }
JonFreeman 6:f289a49c1eae 245
JonFreeman 7:6deaeace9a3e 246 extern double rpm2mph ;
JonFreeman 7:6deaeace9a3e 247 void mph_cmd (struct parameters & a) // to report miles per hour
JonFreeman 7:6deaeace9a3e 248 {
JonFreeman 8:93203f473f6e 249 if (a.respond) {
JonFreeman 7:6deaeace9a3e 250 uint32_t dest[3];
JonFreeman 7:6deaeace9a3e 251 read_RPM (dest); // gets rpm for each motor
JonFreeman 8:93203f473f6e 252 a.com->printf ("mph%c %.3f\r", mode_bytes[ID], (double)(dest[0] + dest[1]) * rpm2mph / 2.0);
JonFreeman 8:93203f473f6e 253 }
JonFreeman 7:6deaeace9a3e 254 }
JonFreeman 7:6deaeace9a3e 255
JonFreeman 6:f289a49c1eae 256 void menucmd (struct parameters & a);
JonFreeman 6:f289a49c1eae 257
JonFreeman 6:f289a49c1eae 258 void vi_cmd (struct parameters & a)
JonFreeman 6:f289a49c1eae 259 {
JonFreeman 6:f289a49c1eae 260 // if (a.respond)
JonFreeman 6:f289a49c1eae 261 // com->printf ("In setVI, setting V to %.2f, I %.2f\r\n", a.dbl[0], a.dbl[1]);
JonFreeman 6:f289a49c1eae 262 setVI (a.dbl[0] / 100.0, a.dbl[1] / 100.0);
JonFreeman 6:f289a49c1eae 263 }
JonFreeman 6:f289a49c1eae 264
JonFreeman 6:f289a49c1eae 265 void v_cmd (struct parameters & a)
JonFreeman 6:f289a49c1eae 266 {
JonFreeman 6:f289a49c1eae 267 // if (a.respond)
JonFreeman 6:f289a49c1eae 268 // com->printf ("In setV, setting V to %.2f\r\n", a.dbl[0]);
JonFreeman 6:f289a49c1eae 269 setV (a.dbl[0] / 100.0);
JonFreeman 6:f289a49c1eae 270 }
JonFreeman 6:f289a49c1eae 271
JonFreeman 6:f289a49c1eae 272 void i_cmd (struct parameters & a)
JonFreeman 6:f289a49c1eae 273 {
JonFreeman 6:f289a49c1eae 274 // if (a.respond)
JonFreeman 7:6deaeace9a3e 275 // a.com->printf ("In setI, setting I to %.2f\r\n", a.dbl[0]);
JonFreeman 6:f289a49c1eae 276 setI (a.dbl[0] / 100.0);
JonFreeman 6:f289a49c1eae 277 }
JonFreeman 6:f289a49c1eae 278
JonFreeman 6:f289a49c1eae 279 void kd_cmd (struct parameters & a) // kick the watchdog
JonFreeman 6:f289a49c1eae 280 {
JonFreeman 6:f289a49c1eae 281 WatchDog = WATCHDOG_RELOAD + (I_Am() & 0x0f);
JonFreeman 7:6deaeace9a3e 282 // a.com->printf ("Poked %d up Dog\r\n", WatchDog);
JonFreeman 6:f289a49c1eae 283 }
JonFreeman 6:f289a49c1eae 284
JonFreeman 6:f289a49c1eae 285 void who_cmd (struct parameters & a)
JonFreeman 6:f289a49c1eae 286 {
JonFreeman 6:f289a49c1eae 287 int i = I_Am ();
JonFreeman 6:f289a49c1eae 288 if (I_Am() == a.target_unit)
JonFreeman 7:6deaeace9a3e 289 a.com->printf ("who%c\r\n", a.target_unit);
JonFreeman 6:f289a49c1eae 290 }
JonFreeman 6:f289a49c1eae 291
JonFreeman 10:e40d8724268a 292 extern void rcin_report () ;
JonFreeman 10:e40d8724268a 293 void rcin_pccmd (struct parameters & a)
JonFreeman 10:e40d8724268a 294 {
JonFreeman 10:e40d8724268a 295 rcin_report ();
JonFreeman 10:e40d8724268a 296 }
JonFreeman 10:e40d8724268a 297
JonFreeman 6:f289a49c1eae 298 struct kb_command {
JonFreeman 6:f289a49c1eae 299 const char * cmd_word; // points to text e.g. "menu"
JonFreeman 6:f289a49c1eae 300 const char * explan;
JonFreeman 6:f289a49c1eae 301 void (*f)(struct parameters &); // points to function
JonFreeman 6:f289a49c1eae 302 } ;
JonFreeman 6:f289a49c1eae 303
JonFreeman 9:ac2412df01be 304
JonFreeman 9:ac2412df01be 305 /**
JonFreeman 9:ac2412df01be 306 struct kb_command const loco_command_list[] = {
JonFreeman 9:ac2412df01be 307 List of commands accepted from external controller through opto isolated com port 9600, 8,n,1
JonFreeman 9:ac2412df01be 308 */
JonFreeman 7:6deaeace9a3e 309 struct kb_command const loco_command_list[] = {
JonFreeman 6:f289a49c1eae 310 {"ls", "Lists available commands", menucmd},
JonFreeman 6:f289a49c1eae 311 {"?", "Lists available commands, same as ls", menucmd},
JonFreeman 6:f289a49c1eae 312 {"fw", "forward", fw_cmd},
JonFreeman 6:f289a49c1eae 313 {"re", "reverse", re_cmd},
JonFreeman 6:f289a49c1eae 314 {"rb", "regen brake 0 to 99 %", rb_cmd},
JonFreeman 6:f289a49c1eae 315 {"hb", "hand brake", hb_cmd},
JonFreeman 6:f289a49c1eae 316 {"v", "set motors V percent RANGE 0 to 100", v_cmd},
JonFreeman 6:f289a49c1eae 317 {"i", "set motors I percent RANGE 0 to 100", i_cmd},
JonFreeman 6:f289a49c1eae 318 {"vi", "set motors V and I percent RANGE 0 to 100", vi_cmd},
JonFreeman 8:93203f473f6e 319 {"who", "search for connected units, e.g. 3who returs 'who3' if found", who_cmd},
JonFreeman 6:f289a49c1eae 320 {"mode", "read or set params in eeprom", mode_cmd},
JonFreeman 6:f289a49c1eae 321 {"erase", "set eeprom contents to all 0xff", erase_cmd},
JonFreeman 6:f289a49c1eae 322 {"tem", "report temperature", temperature_cmd},
JonFreeman 6:f289a49c1eae 323 {"kd", "kick the dog, reloads WatchDog", kd_cmd},
JonFreeman 8:93203f473f6e 324 {"wden", "enable watchdog if modes allow", wden_lococmd},
JonFreeman 8:93203f473f6e 325 {"wddi", "disable watchdog always", wddi_lococmd},
JonFreeman 6:f289a49c1eae 326 {"rpm", "read motor pair speeds", rpm_cmd},
JonFreeman 8:93203f473f6e 327 {"mph", "read loco speed miles per hour", mph_cmd},
JonFreeman 6:f289a49c1eae 328 {"rvi", "read most recent values sent to pwms", rvi_cmd},
JonFreeman 6:f289a49c1eae 329 {"rdi", "read motor currents and power voltage", rdi_cmd},
JonFreeman 8:93203f473f6e 330 {"bc", "bogie constants - wheel dia, motor pinion, wheel gear", bogie_constants_report_cmd}, // OBSOLETE, replaced by 'gbb'
JonFreeman 8:93203f473f6e 331 {"gbb", "get bogie bytes from eeprom and report", gbb_cmd},
JonFreeman 6:f289a49c1eae 332 {"nu", "do nothing", null_cmd},
JonFreeman 6:f289a49c1eae 333 };
JonFreeman 6:f289a49c1eae 334
JonFreeman 7:6deaeace9a3e 335 //const int numof_loco_menu_items = sizeof(loco_command_list) / sizeof(kb_command);
JonFreeman 7:6deaeace9a3e 336
JonFreeman 7:6deaeace9a3e 337
JonFreeman 9:ac2412df01be 338 /**
JonFreeman 9:ac2412df01be 339 struct kb_command const loco_command_list[] = {
JonFreeman 9:ac2412df01be 340 List of commands accepted from external pc through non-opto isolated com port 9600, 8,n,1
JonFreeman 9:ac2412df01be 341 */
JonFreeman 7:6deaeace9a3e 342 struct kb_command const pc_command_list[] = {
JonFreeman 7:6deaeace9a3e 343 {"ls", "Lists available commands", menucmd},
JonFreeman 7:6deaeace9a3e 344 {"?", "Lists available commands, same as ls", menucmd},
JonFreeman 8:93203f473f6e 345 {"mtypes", "report types of motors found", mt_cmd},
JonFreeman 8:93203f473f6e 346 {"pf", "try changing FastPWM prescaler values", pf_cmd},
JonFreeman 8:93203f473f6e 347 {"pot", "read drivers control pot", pot_cmd},
JonFreeman 7:6deaeace9a3e 348 {"fw", "forward", fw_cmd},
JonFreeman 7:6deaeace9a3e 349 {"re", "reverse", re_cmd},
JonFreeman 7:6deaeace9a3e 350 {"rb", "regen brake 0 to 99 %", rb_cmd},
JonFreeman 7:6deaeace9a3e 351 {"hb", "hand brake", hb_cmd},
JonFreeman 7:6deaeace9a3e 352 {"v", "set motors V percent RANGE 0 to 100", v_cmd},
JonFreeman 7:6deaeace9a3e 353 {"i", "set motors I percent RANGE 0 to 100", i_cmd},
JonFreeman 7:6deaeace9a3e 354 {"vi", "set motors V and I percent RANGE 0 to 100", vi_cmd},
JonFreeman 8:93203f473f6e 355 {"who", "search for connected units, e.g. 3who returs 'who3' if found", who_cmd},
JonFreeman 7:6deaeace9a3e 356 {"mode", "read or set params in eeprom", mode_cmd},
JonFreeman 7:6deaeace9a3e 357 {"erase", "set eeprom contents to all 0xff", erase_cmd},
JonFreeman 7:6deaeace9a3e 358 {"tem", "report temperature", temperature_cmd},
JonFreeman 7:6deaeace9a3e 359 {"kd", "kick the dog, reloads WatchDog", kd_cmd},
JonFreeman 8:93203f473f6e 360 {"wden", "enable watchdog if modes allow", wden_pccmd},
JonFreeman 8:93203f473f6e 361 {"wddi", "disable watchdog always", wddi_pccmd},
JonFreeman 10:e40d8724268a 362 {"rcin", "Report Radio Control Input stuff", rcin_pccmd},
JonFreeman 7:6deaeace9a3e 363 {"rpm", "read motor pair speeds", rpm_cmd},
JonFreeman 7:6deaeace9a3e 364 {"mph", "read loco speed miles per hour", mph_cmd},
JonFreeman 7:6deaeace9a3e 365 {"rvi", "read most recent values sent to pwms", rvi_cmd},
JonFreeman 7:6deaeace9a3e 366 {"rdi", "read motor currents and power voltage", rdi_cmd},
JonFreeman 7:6deaeace9a3e 367 {"bc", "bogie constants - wheel dia, motor pinion, wheel gear", bogie_constants_report_cmd},
JonFreeman 8:93203f473f6e 368 {"gbb", "get bogie bytes from eeprom and report", gbb_cmd}, // OBSOLETE, replaced by 'gbb'
JonFreeman 7:6deaeace9a3e 369 {"nu", "do nothing", null_cmd},
JonFreeman 7:6deaeace9a3e 370 };
JonFreeman 7:6deaeace9a3e 371
JonFreeman 7:6deaeace9a3e 372 void setup_comms () {
JonFreeman 7:6deaeace9a3e 373 pccom.com = & pc;
JonFreeman 7:6deaeace9a3e 374 pccom.command_list = pc_command_list;
JonFreeman 7:6deaeace9a3e 375 pccom.numof_menu_items = sizeof(pc_command_list) / sizeof(kb_command);
JonFreeman 7:6deaeace9a3e 376 pccom.cl_index = 0;
JonFreeman 7:6deaeace9a3e 377 pccom.gp_i = 0; // general puropse integer, not used to 30/4/2018
JonFreeman 7:6deaeace9a3e 378 pccom.resp_always = true;
JonFreeman 7:6deaeace9a3e 379 lococom.com = & com2;
JonFreeman 7:6deaeace9a3e 380 lococom.command_list = loco_command_list;
JonFreeman 7:6deaeace9a3e 381 lococom.numof_menu_items = sizeof(loco_command_list) / sizeof(kb_command);
JonFreeman 7:6deaeace9a3e 382 lococom.cl_index = 0;
JonFreeman 7:6deaeace9a3e 383 lococom.gp_i = 0; // general puropse integer, toggles 0 / 1 to best guess source of rpm
JonFreeman 7:6deaeace9a3e 384 lococom.resp_always = false;
JonFreeman 7:6deaeace9a3e 385 }
JonFreeman 7:6deaeace9a3e 386
JonFreeman 7:6deaeace9a3e 387
JonFreeman 6:f289a49c1eae 388 void menucmd (struct parameters & a)
JonFreeman 6:f289a49c1eae 389 {
JonFreeman 6:f289a49c1eae 390 if (a.respond) {
JonFreeman 10:e40d8724268a 391 a.com->printf("\r\n\nDual BLDC ESC type STM3 2018\r\nAt menucmd function - listing commands:-\r\n");
JonFreeman 7:6deaeace9a3e 392 for(int i = 0; i < a.numof_menu_items; i++)
JonFreeman 7:6deaeace9a3e 393 a.com->printf("[%s]\t\t%s\r\n", a.command_list[i].cmd_word, a.command_list[i].explan);
JonFreeman 7:6deaeace9a3e 394 a.com->printf("End of List of Commands\r\n");
JonFreeman 6:f289a49c1eae 395 }
JonFreeman 6:f289a49c1eae 396 }
JonFreeman 6:f289a49c1eae 397
JonFreeman 6:f289a49c1eae 398 /*
JonFreeman 6:f289a49c1eae 399 New - March 2018
JonFreeman 6:f289a49c1eae 400 Using opto isolated serial port, paralleled up using same pair to multiple boards running this code.
JonFreeman 6:f289a49c1eae 401 New feature - commands have optional prefix digit 0-9 indicating which unit message is addressed to.
JonFreeman 6:f289a49c1eae 402 Commands without prefix digit - broadcast to all units, all to obey but none to respond.
JonFreeman 6:f289a49c1eae 403 Only units recognising its address from prefix digit may respond. This avoids bus contention.
JonFreeman 6:f289a49c1eae 404 But for BROADCAST commands, '0' may respond on behalf of the group
JonFreeman 6:f289a49c1eae 405 */
JonFreeman 6:f289a49c1eae 406 //void command_line_interpreter (void const *argument)
JonFreeman 7:6deaeace9a3e 407 void cli_core (struct parameters & a) {
JonFreeman 7:6deaeace9a3e 408 const int MAX_CMD_LEN = 120;
JonFreeman 7:6deaeace9a3e 409 int ch, IAm = I_Am();
JonFreeman 7:6deaeace9a3e 410 char * pEnd;//, * cmd_line_ptr;
JonFreeman 7:6deaeace9a3e 411 while (a.com->readable()) {
JonFreeman 7:6deaeace9a3e 412 ch = a.com->getc();
JonFreeman 7:6deaeace9a3e 413 if (a.cl_index > MAX_CMD_LEN) { // trap out stupidly long command lines
JonFreeman 7:6deaeace9a3e 414 a.com->printf ("Error!! Stupidly long cmd line\r\n");
JonFreeman 7:6deaeace9a3e 415 a.cl_index = 0;
JonFreeman 7:6deaeace9a3e 416 }
JonFreeman 7:6deaeace9a3e 417 if(ch != '\r') // was this the 'Enter' key?
JonFreeman 7:6deaeace9a3e 418 a.cmd_line[a.cl_index++] = ch; // added char to command being assembled
JonFreeman 7:6deaeace9a3e 419 else { // key was CR, may or may not be command to lookup
JonFreeman 7:6deaeace9a3e 420 a.target_unit = BROADCAST; // Set to BROADCAST default once found command line '\r'
JonFreeman 7:6deaeace9a3e 421 a.cmd_line_ptr = a.cmd_line;
JonFreeman 7:6deaeace9a3e 422 a.cmd_line[a.cl_index] = 0; // null terminate command string
JonFreeman 7:6deaeace9a3e 423 if(a.cl_index) { // If have got some chars to lookup
JonFreeman 7:6deaeace9a3e 424 int i, wrdlen;
JonFreeman 7:6deaeace9a3e 425 if (isdigit(a.cmd_line[0])) { // Look for command with prefix digit
JonFreeman 7:6deaeace9a3e 426 a.cmd_line_ptr++; // point past identified digit prefix
JonFreeman 7:6deaeace9a3e 427 a.target_unit = a.cmd_line[0]; // '0' to '9'
JonFreeman 7:6deaeace9a3e 428 //com->printf ("Got prefix %c\r\n", cmd_line[0]);
JonFreeman 7:6deaeace9a3e 429 }
JonFreeman 7:6deaeace9a3e 430 for (i = 0; i < a.numof_menu_items; i++) { // Look for input match in command list
JonFreeman 7:6deaeace9a3e 431 wrdlen = strlen(a.command_list[i].cmd_word);
JonFreeman 7:6deaeace9a3e 432 if(strncmp(a.command_list[i].cmd_word, a.cmd_line_ptr, wrdlen) == 0 && !isalpha(a.cmd_line_ptr[wrdlen])) { // If match found
JonFreeman 7:6deaeace9a3e 433 for (int k = 0; k < MAX_PARAMS; k++) {
JonFreeman 7:6deaeace9a3e 434 a.dbl[k] = 0.0;
JonFreeman 7:6deaeace9a3e 435 }
JonFreeman 7:6deaeace9a3e 436 a.position_in_list = i;
JonFreeman 7:6deaeace9a3e 437 a.numof_dbls = 0;
JonFreeman 7:6deaeace9a3e 438 pEnd = a.cmd_line_ptr + wrdlen;
JonFreeman 7:6deaeace9a3e 439 while (*pEnd) { // Assemble all numerics as doubles
JonFreeman 7:6deaeace9a3e 440 a.dbl[a.numof_dbls++] = strtod (pEnd, &pEnd);
JonFreeman 7:6deaeace9a3e 441 while (*pEnd && !isdigit(*pEnd) && '-' != *pEnd && '+' != *pEnd) {
JonFreeman 7:6deaeace9a3e 442 pEnd++;
JonFreeman 7:6deaeace9a3e 443 }
JonFreeman 7:6deaeace9a3e 444 }
JonFreeman 7:6deaeace9a3e 445 //com->printf ("\r\n"); // Not allowed as many may output this.
JonFreeman 7:6deaeace9a3e 446 //for (int k = 0; k < param_block.numof_dbls; k++)
JonFreeman 7:6deaeace9a3e 447 // com->printf ("Read %.3f\r\n", param_block.dbl[k]);
JonFreeman 7:6deaeace9a3e 448 // param_block.times[i] = clock();
JonFreeman 7:6deaeace9a3e 449 // a.respond = false;
JonFreeman 7:6deaeace9a3e 450 a.respond = a.resp_always;
JonFreeman 7:6deaeace9a3e 451 if (((a.target_unit == BROADCAST) && (IAm == '0')) || (IAm == a.target_unit))
JonFreeman 7:6deaeace9a3e 452 a.respond = true; // sorted 26/4/18
JonFreeman 7:6deaeace9a3e 453 // All boards to obey BROADCAST command, only specific board to obey number prefixed command
JonFreeman 7:6deaeace9a3e 454 if ((a.target_unit == BROADCAST) || (IAm == a.target_unit))
JonFreeman 7:6deaeace9a3e 455 a.command_list[i].f(a); // execute command if addressed to this unit
JonFreeman 7:6deaeace9a3e 456 i = a.numof_menu_items + 1; // to exit for loop
JonFreeman 7:6deaeace9a3e 457 } // end of match found
JonFreeman 7:6deaeace9a3e 458 } // End of for numof_menu_items
JonFreeman 7:6deaeace9a3e 459 if(i == a.numof_menu_items)
JonFreeman 7:6deaeace9a3e 460 a.com->printf("No Match Found for CMD [%s]\r\n", a.cmd_line);
JonFreeman 7:6deaeace9a3e 461 } // End of If have got some chars to lookup
JonFreeman 7:6deaeace9a3e 462 //com->printf("\r\n>");
JonFreeman 7:6deaeace9a3e 463 a.cl_index = 0;
JonFreeman 7:6deaeace9a3e 464 } // End of else key was CR, may or may not be command to lookup
JonFreeman 7:6deaeace9a3e 465 } // End of while (com->readable())
JonFreeman 7:6deaeace9a3e 466 }
JonFreeman 7:6deaeace9a3e 467
JonFreeman 7:6deaeace9a3e 468 void command_line_interpreter_pc () {
JonFreeman 7:6deaeace9a3e 469 cli_core (pccom);
JonFreeman 7:6deaeace9a3e 470 }
JonFreeman 7:6deaeace9a3e 471 void command_line_interpreter_loco () {
JonFreeman 7:6deaeace9a3e 472 cli_core (lococom);
JonFreeman 7:6deaeace9a3e 473 }
JonFreeman 7:6deaeace9a3e 474
JonFreeman 6:f289a49c1eae 475 void command_line_interpreter ()
JonFreeman 6:f289a49c1eae 476 {
JonFreeman 7:6deaeace9a3e 477 /* const int MAX_CMD_LEN = 120;
JonFreeman 6:f289a49c1eae 478 static char cmd_line[MAX_CMD_LEN + 4];
JonFreeman 6:f289a49c1eae 479 static int cl_index = 0;
JonFreeman 6:f289a49c1eae 480 int ch, IAm = I_Am();
JonFreeman 6:f289a49c1eae 481 char * pEnd, * cmd_line_ptr;
JonFreeman 6:f289a49c1eae 482 static struct parameters param_block ;
JonFreeman 6:f289a49c1eae 483 com = &com2;
JonFreeman 6:f289a49c1eae 484 while (com->readable()) {
JonFreeman 6:f289a49c1eae 485 // ch = tolower(com->getc());
JonFreeman 6:f289a49c1eae 486 ch = com->getc();
JonFreeman 6:f289a49c1eae 487 if (cl_index > MAX_CMD_LEN) { // trap out stupidly long command lines
JonFreeman 6:f289a49c1eae 488 com->printf ("Error!! Stupidly long cmd line\r\n");
JonFreeman 6:f289a49c1eae 489 cl_index = 0;
JonFreeman 6:f289a49c1eae 490 }
JonFreeman 6:f289a49c1eae 491 if(ch != '\r') // was this the 'Enter' key?
JonFreeman 6:f289a49c1eae 492 cmd_line[cl_index++] = ch; // added char to command being assembled
JonFreeman 6:f289a49c1eae 493 else { // key was CR, may or may not be command to lookup
JonFreeman 6:f289a49c1eae 494 param_block.target_unit = BROADCAST; // Set to BROADCAST default once found command line '\r'
JonFreeman 6:f289a49c1eae 495 cmd_line_ptr = cmd_line;
JonFreeman 6:f289a49c1eae 496 cmd_line[cl_index] = 0; // null terminate command string
JonFreeman 6:f289a49c1eae 497 if(cl_index) { // If have got some chars to lookup
JonFreeman 6:f289a49c1eae 498 int i, wrdlen;
JonFreeman 6:f289a49c1eae 499 if (isdigit(cmd_line[0])) { // Look for command with prefix digit
JonFreeman 6:f289a49c1eae 500 cmd_line_ptr++; // point past identified digit prefix
JonFreeman 6:f289a49c1eae 501 param_block.target_unit = cmd_line[0]; // '0' to '9'
JonFreeman 6:f289a49c1eae 502 //com->printf ("Got prefix %c\r\n", cmd_line[0]);
JonFreeman 6:f289a49c1eae 503 }
JonFreeman 7:6deaeace9a3e 504 for (i = 0; i < a.numof_menu_items; i++) { // Look for input match in command list
JonFreeman 7:6deaeace9a3e 505 wrdlen = strlen(a.command_list[i].cmd_word);
JonFreeman 7:6deaeace9a3e 506 if(strncmp(a.command_list[i].cmd_word, a.cmd_line_ptr, wrdlen) == 0 && !isalpha(a.cmd_line_ptr[wrdlen])) { // If match found
JonFreeman 6:f289a49c1eae 507 for (int k = 0; k < MAX_PARAMS; k++) {
JonFreeman 6:f289a49c1eae 508 param_block.dbl[k] = 0.0;
JonFreeman 6:f289a49c1eae 509 }
JonFreeman 6:f289a49c1eae 510 param_block.position_in_list = i;
JonFreeman 6:f289a49c1eae 511 // param_block.last_time = clock ();
JonFreeman 6:f289a49c1eae 512 param_block.numof_dbls = 0;
JonFreeman 6:f289a49c1eae 513 pEnd = cmd_line_ptr + wrdlen;
JonFreeman 6:f289a49c1eae 514 while (*pEnd) { // Assemble all numerics as doubles
JonFreeman 6:f289a49c1eae 515 param_block.dbl[param_block.numof_dbls++] = strtod (pEnd, &pEnd);
JonFreeman 6:f289a49c1eae 516 while (*pEnd && !isdigit(*pEnd) && '-' != *pEnd && '+' != *pEnd) {
JonFreeman 6:f289a49c1eae 517 pEnd++;
JonFreeman 6:f289a49c1eae 518 }
JonFreeman 6:f289a49c1eae 519 }
JonFreeman 6:f289a49c1eae 520 //com->printf ("\r\n"); // Not allowed as many may output this.
JonFreeman 6:f289a49c1eae 521 //for (int k = 0; k < param_block.numof_dbls; k++)
JonFreeman 6:f289a49c1eae 522 // com->printf ("Read %.3f\r\n", param_block.dbl[k]);
JonFreeman 6:f289a49c1eae 523 // param_block.times[i] = clock();
JonFreeman 6:f289a49c1eae 524 param_block.respond = false;
JonFreeman 6:f289a49c1eae 525 if (((param_block.target_unit == BROADCAST) && (IAm == '0')) || (IAm == param_block.target_unit))
JonFreeman 6:f289a49c1eae 526 param_block.respond = true; // sorted 26/4/18
JonFreeman 6:f289a49c1eae 527 // All boards to obey BROADCAST command, only specific board to obey number prefixed command
JonFreeman 6:f289a49c1eae 528 if ((param_block.target_unit == BROADCAST) || (IAm == param_block.target_unit))
JonFreeman 6:f289a49c1eae 529 command_list[i].f(param_block); // execute command if addressed to this unit
JonFreeman 6:f289a49c1eae 530 i = numof_menu_items + 1; // to exit for loop
JonFreeman 6:f289a49c1eae 531 } // end of match found
JonFreeman 6:f289a49c1eae 532 } // End of for numof_menu_items
JonFreeman 6:f289a49c1eae 533 if(i == numof_menu_items)
JonFreeman 6:f289a49c1eae 534 com->printf("No Match Found for CMD [%s]\r\n", cmd_line);
JonFreeman 6:f289a49c1eae 535 } // End of If have got some chars to lookup
JonFreeman 6:f289a49c1eae 536 //com->printf("\r\n>");
JonFreeman 6:f289a49c1eae 537 cl_index = 0;
JonFreeman 6:f289a49c1eae 538 } // End of else key was CR, may or may not be command to lookup
JonFreeman 6:f289a49c1eae 539 } // End of while (com->readable())
JonFreeman 6:f289a49c1eae 540 // Thread::wait(20); // Using RTOS on this project
JonFreeman 7:6deaeace9a3e 541 // }*/
JonFreeman 6:f289a49c1eae 542 }
JonFreeman 6:f289a49c1eae 543
JonFreeman 6:f289a49c1eae 544