Touch screen drivers control dashboard for miniature locomotive. Features meters for speed, volts, power. Switches for lights, horns. Drives multiple STM3_ESC brushless motor controllers for complete brushless loco system as used in "The Brute" - www.jons-workshop.com
Dependencies: TS_DISCO_F746NG mbed Servo LCD_DISCO_F746NG BSP_DISCO_F746NG QSPI_DISCO_F746NG AsyncSerial FastPWM
cli_TS_nortos.cpp
- Committer:
- JonFreeman
- Date:
- 2018-06-22
- Revision:
- 10:0bdfd342f393
- Parent:
- cli_nortos.cpp@ 7:3b1f44cd4735
File content as of revision 10:0bdfd342f393:
//Loco_TS_2018 #include "mbed.h" //#include "BufferedSerial.h" #include "AsyncSerial.hpp" #include <cctype> #include "Electric_Loco.h" using namespace std; //extern int I_Am () ; // Returns boards id number as ASCII char '0', '1' etc. Code for Broadcast = '\r' //typedef double fl_typ; // struct parameters pccom, lococom; void clicore (struct parameters & a) ; const int BROADCAST = '\r'; // WithOUT RTOS extern Serial pc; extern AsyncSerial com; extern void send_test () ; void null_cmd (struct parameters & a) { pc.printf ("At null_cmd, parameters : First %.3f, second %.3f\r\n", a.dbl[0], a.dbl[1]); } extern struct multi_bogie_options detected_bogie_options; /* struct single_bogie_options { char motoradir, motorbdir, gang, svo1, svo2, comm_src, id, wheeldia, motpin, wheelgear, spare; } ; */ bool validate_mode_bytes (char * bytes) { int q; for (int i = 0; i < numof_eeprom_options; i++) { q = (int)bytes[i]; if (i == ID) q |= '0'; if (q < option_list[i].min || q > option_list[i].max) return false; } return true; } extern uint32_t sys_timer_32Hz; char * globdest = 0; // findable by code here responding to gbb bool globflag; // findable by code here responding to gbb bool get_bogie_bytes (int bogie_id, char * dest) { // bogie_id could be e.g. 3, or '3' NOTE 22/06/2018 yet to write matching fn in bogie code uint32_t localtime = sys_timer_32Hz + 50; // for timeout bogie_id |= '0'; // ***** NOTE ***** THIS IS A BLOCKING FUNCTION globdest = dest; globflag = false; com.printf ("%cgbb\r", bogie_id); // issue gbb command to get bogie bytes to be coded into bogie pc.printf ("Issued %cgbb\r\n", bogie_id); while (!globflag && (localtime > sys_timer_32Hz)) { clicore (pccom); clicore (lococom); } return globflag; // Returns false on timeout } void make_option_bytes_from_dbls (double * src, char * dest) { // cli has sorted text string into array of doubles for (int i = 0; i < numof_eeprom_options; i++) { // Turn this to string of mode bytes as stored in eeprom dest[i] = (char)src[i]; } } char * make_str_from_option_bytes (char * src, char * dest) { // Use for easy readback to pc dest[0] = 0; // string null terminator for (int i = 0; i < numof_eeprom_options; i++) { if (i) strcat (dest, " "); // single space between outputs, no leading or trailing space sprintf (dest + strlen(dest), "%d", (int)src[i]); } return dest; } void buggertest (char * src) { // src is string of option bytes read from eeprom } void mode_cmd (struct parameters & a) { int error = 0, q; // bool valid_params = false; pc.printf ("At mode_cmd, numof parameters found=%d : numof parameters required=%d\r\n", a.numof_dbls, numof_eeprom_options); for (int i = 0; i < numof_eeprom_options; i++) { q = (int)a.dbl[i]; if (i == ID) q |= '0'; // badf = false; if (q < option_list[i].min || q > option_list[i].max) { // badf = true; error++; } // pc.printf ("Parameter %s, entered %d, %s\r\n",option_list[i].t , q, badf ? "Bad":"Good"); } if (a.numof_dbls == numof_eeprom_options && !error) { // correct num of options presented, proceed to blow eeproms pc.printf ("Congrats - looks like valid input!!\r\n"); // sprintf (txt, "%cmode",(int)a.dbl[ID]); com.putc ((int)a.dbl[ID]); // have already checked is valid in range com.printf ("mode"); for (int i = 0; i < numof_eeprom_options; i++) com.printf (" %d", (int)a.dbl[i]); com.putc ('\r'); pc.printf ("Have sent mode parameters down to %d\r\n", (int)a.dbl[ID]); } else { // report only } } void menucmd (struct parameters & a); void kd_cmd (struct parameters & a) // kick the watchdog { } void uptem_cmd (struct parameters & a) // get temperature reading from bogie { int bog_id = (int)a.dbl[0] | '0'; int temp = (int)a.dbl[1]; pc.printf ("Read Temp %d from bogie id %d\r\n", temp, bog_id); } void gbb_cmd (struct parameters & a) // handling bogie response to get bogie constants - bogie returns as string of nums in hex format { // decode bogie bytes and place in global array 'globdest', setting global 'globflag' when done. Code issuing 'gbb' deals with timeout pc.printf ("Arrived at gbb_cmd\r\n"); if (globdest == 0) { pc.printf ("Fatal null ptr in gbb_cmd\r\n"); return; } pc.printf ("Responding to gbb back from bogie\r\n"); for (int i = 0; i < numof_eeprom_options; i++) { globdest[i] = (char)a.dbl[i]; } globflag = true; } void upbc_cmd (struct parameters & a) // get bogie constants - wheel dia, motor pinion, wheel gear ** SUPERCEDED BY 'gbb' { int bog_id = (int)a.dbl[0] | '0'; int wheeldia = (int)a.dbl[1]; int motorpin = (int)a.dbl[2]; int wheelgear = (int)a.dbl[3]; pc.printf ("Read bogie constants from bogie id %d,wheel dia %d, motorpin %d, wheel gear %d\r\n", bog_id, wheeldia, motorpin, wheelgear); for (int i = 0; i < MAX_BOGIES; i++) { if (detected_bogie_options.bogie[i].p[ID] == bog_id) { detected_bogie_options.bogie[i].p[WHEELDIA] = wheeldia; detected_bogie_options.bogie[i].p[MOTPIN] = motorpin; detected_bogie_options.bogie[i].p[WHEELGEAR] = wheelgear; pc.printf ("Stored in detected_bogie_options [%d]\r\n", i); i = MAX_BOGIES; } } } extern void rpm_push (struct parameters & a) ; void uprpm_cmd (struct parameters & a) // controller rec'd rpm from driver boards { rpm_push (a); // a.gp_i ^= 1; // toggle lsb } void uprdi_cmd (struct parameters & a) // controller rec'd rpm from driver boards { // pc.printf ("RPM %d %d\r\n", (int)a.dbl[0], (int)a.dbl[1]); } /*void who_cmd (struct parameters & a) { int i = I_Am (); if (I_Am() == a.target_unit) pc.printf ("Hi there, I am %c\r\n", a.target_unit); }*/ struct kb_command { const char * cmd_word; // points to text e.g. "menu" const char * explan; void (*f)(struct parameters &); // points to function } ; struct kb_command const command_list[] = { {"ls", "Lists available commands", menucmd}, {"?", "Lists available commands, same as ls", menucmd}, // {"fw", "forward", fw_cmd}, // {"re", "reverse", re_cmd}, // {"rb", "regen brake 0 to 99 %", rb_cmd}, // {"hb", "hand brake", hb_cmd}, // {"v", "set motors V percent RANGE 0 to 100", v_cmd}, // {"i", "set motors I percent RANGE 0 to 100", i_cmd}, // {"vi", "set motors V and I percent RANGE 0 to 100", vi_cmd}, // {"who", "search for connected units, e.g. 3who returs 'Hi there' if found", who_cmd}, {"mode", "read or set params in eeprom", mode_cmd}, // {"erase", "set eeprom contents to all 0xff", erase_cmd}, {"kd", "kick the dog", kd_cmd}, // {"rpm", "rpm reading from 2 motors", uprpm_cmd}, {"nu", "do nothing", null_cmd}, }; const int numof_menu_items = sizeof(command_list) / sizeof(kb_command); void menucmd (struct parameters & a) { // struct kb_command const * cl = command_list; pc.printf("\r\n\nTS_2018 Locomotive Touch Screen Controller\r\nAt menucmd function - listing commands:-\r\n"); for(int i = 0; i < numof_menu_items; i++) pc.printf("[%s]\t\t%s\r\n", command_list[i].cmd_word, command_list[i].explan); pc.printf("End of List of Commands\r\n"); } struct kb_command const loco_command_list[] = { {"ls", "Lists available commands", menucmd}, {"?", "Lists available commands, same as ls", menucmd}, {"rpm", "rpm reading from 2 motors", uprpm_cmd}, {"rdi", "rpm reading from 2 motors", uprdi_cmd}, {"tem", "report temperature", uptem_cmd}, {"bc", "bogie constants - wheel dia, motor pinion, wheel gear", upbc_cmd}, {"gbb", "get bogie bytes, all of them", gbb_cmd}, {"nu", "do nothing", null_cmd}, } ; /*struct parameters { struct kb_command const * clist; char cmd_line[120]; char * cmd_line_ptr; int32_t position_in_list, numof_dbls, target_unit, numof_menu_items; double dbl[MAX_PARAMS]; bool respond; } ; */ int getc (int which_port) { if (which_port == 0) return pc.getc (); if (which_port == 1) return com.getc (); return -1; } int readable (int which_port) { if (which_port == 0) return pc.readable (); if (which_port == 1) return com.readable (); return -1; } void setup_pccom () { pccom.clist = command_list; pccom.numof_menu_items = sizeof(command_list) / sizeof(kb_command); pccom.com_no = 0; pccom.cl_index = 0; pccom.gp_i = 0; // general puropse integer, not used to 30/4/2018 } void setup_lococom () { lococom.clist = loco_command_list; lococom.numof_menu_items = sizeof(loco_command_list) / sizeof(kb_command); lococom.com_no = 1; lococom.cl_index = 0; lococom.gp_i = 0; // general puropse integer, toggles 0 / 1 to best guess source of rpm } void clicore (struct parameters & a) { int ch; char * pEnd; while (readable(a.com_no)) { ch = getc (a.com_no); if(ch != '\r') { // was this the 'Enter' key? // if(ch != '\r' && ch != '\n') // was this the 'Enter' key? // if (ch != '\n') a.cmd_line[a.cl_index++] = ch; // added char to command being assembled a.cmd_line[a.cl_index++] = ch; // added char to command being assembled } else { // key was CR, may or may not be command to lookup a.target_unit = BROADCAST; // Broadcast a.cmd_line_ptr = a.cmd_line; a.cmd_line[a.cl_index] = 0; // null terminate command string if(a.cl_index) { // If have got some chars to lookup int i, wrdlen; if (isdigit(a.cmd_line[0])) { // Look for command with prefix digit a.cmd_line_ptr++; // point past identified digit prefix a.target_unit = a.cmd_line[0]; // '0' to '9' //pc.printf ("Got prefix %c\r\n", cmd_line[0]); } for (i = 0; i < a.numof_menu_items; i++) { // Look for input match in command list wrdlen = strlen(a.clist[i].cmd_word); if(strncmp(a.clist[i].cmd_word, a.cmd_line_ptr, wrdlen) == 0 && !isalpha(a.cmd_line_ptr[wrdlen])) { // If match found for (int k = 0; k < MAX_PARAMS; k++) { a.dbl[k] = 0.0; } a.position_in_list = i; a.numof_dbls = 0; pEnd = a.cmd_line_ptr + wrdlen; while (*pEnd) { // Assemble all numerics as doubles a.dbl[a.numof_dbls++] = strtod (pEnd, &pEnd); while (*pEnd && !isdigit(*pEnd) && '-' != *pEnd && '+' != *pEnd) { pEnd++; } } //pc.printf ("\r\n"); // Not allowed as many may output this. //for (int k = 0; k < param_block.numof_dbls; k++) // pc.printf ("Read %.3f\r\n", param_block.dbl[k]); // param_block.times[i] = clock(); // if ((param_block.target_unit == BROADCAST) && (I_Am() == '0')) // param_block.respond = true; a.clist[i].f(a); // execute command i = a.numof_menu_items + 1; // to exit for loop } // end of match found } // End of for numof_menu_items if(i == a.numof_menu_items) pc.printf("No Match Found for CMD [%s]\r\n", a.cmd_line); } // End of If have got some chars to lookup //pc.printf("\r\n>"); a.cl_index = 0; } // End of else key was CR, may or may not be command to lookup } // End of while (pc.readable()) } /* New - March 2018 Using opto isolated serial port, paralleled up using same pair to multiple boards running this code. New feature - commands have optional prefix digit 0-9 indicating which unit message is addressed to. Commands without prefix digit - broadcast to all units, none to respond. Only units recognising its address from prefix digit may respond. This avoids bus contention. But for BROADCAST commands, '0' may respond on behalf of the group */ //void command_line_interpreter (void const *argument) /*void command_line_interpreter () { const int MAX_CMD_LEN = 120; static char cmd_line[MAX_CMD_LEN + 4]; static int cl_index = 0; int ch; char * pEnd, * cmd_line_ptr; static struct parameters param_block ; while (pc.readable()) { ch = pc.getc(); // if (cl_index > MAX_CMD_LEN) { // trap out stupidly long command lines // pc.printf ("Error!! Stupidly long cmd line\r\n"); // cl_index = 0; // } if(ch != '\r') // was this the 'Enter' key? cmd_line[cl_index++] = ch; // added char to command being assembled else { // key was CR, may or may not be command to lookup param_block.target_unit = BROADCAST; // Broadcast cmd_line_ptr = cmd_line; cmd_line[cl_index] = 0; // null terminate command string if(cl_index) { // If have got some chars to lookup int i, wrdlen; if (isdigit(cmd_line[0])) { // Look for command with prefix digit cmd_line_ptr++; // point past identified digit prefix param_block.target_unit = cmd_line[0]; // '0' to '9' //pc.printf ("Got prefix %c\r\n", cmd_line[0]); } for (i = 0; i < numof_menu_items; i++) { // Look for input match in command list wrdlen = strlen(command_list[i].cmd_word); if(strncmp(command_list[i].cmd_word, cmd_line_ptr, wrdlen) == 0 && !isalpha(cmd_line_ptr[wrdlen])) { // If match found for (int k = 0; k < MAX_PARAMS; k++) { param_block.dbl[k] = 0.0; } param_block.position_in_list = i; param_block.numof_dbls = 0; pEnd = cmd_line_ptr + wrdlen; while (*pEnd) { // Assemble all numerics as doubles param_block.dbl[param_block.numof_dbls++] = strtod (pEnd, &pEnd); while (*pEnd && !isdigit(*pEnd) && '-' != *pEnd && '+' != *pEnd) { pEnd++; } } //pc.printf ("\r\n"); // Not allowed as many may output this. //for (int k = 0; k < param_block.numof_dbls; k++) // pc.printf ("Read %.3f\r\n", param_block.dbl[k]); // param_block.times[i] = clock(); // if ((param_block.target_unit == BROADCAST) && (I_Am() == '0')) // param_block.respond = true; command_list[i].f(param_block); // execute command i = numof_menu_items + 1; // to exit for loop } // end of match found } // End of for numof_menu_items if(i == numof_menu_items) pc.printf("No Match Found for CMD [%s]\r\n", cmd_line); } // End of If have got some chars to lookup //pc.printf("\r\n>"); cl_index = 0; } // End of else key was CR, may or may not be command to lookup } // End of while (pc.readable()) // Thread::wait(20); // Using RTOS on this project // } } */