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
//    }
}
*/