Code to drive a CNC machine via a PC LPT port lookalike 25 pin 'D', experiment in 'PC/Mach3' replacement. Designed to compile and run on mbed LPC1768, Freescale KL25Z and Freescale KL46Z. Proved on LPC1768 and KL25Z, problem with serial port on KL46Z. Reads subset of 'G Codes' through usb/serial port and drives 3 stepper/servo drives for X, Y and Z, also similar Step/Dir outputs for spindle motor control. Emulates PC LPT, outputs 'charge pump', proved driving Seig KX3 CNC mill

Dependencies:   MODSERIAL mbed

command_interpreter.cpp

Committer:
JonFreeman
Date:
2014-01-31
Revision:
0:5d0f270bfc87
Child:
1:66ee619f206b

File content as of revision 0:5d0f270bfc87:

#include "mbed.h"
#include "cnc.h"
using namespace std;

extern  Serial pc;
extern  void    pir_updater (struct axis_speeds_element * p)   ;      //  Uses pointer as we may wish to rapid update from circular buffer

double  feed_rate = 1.0;  //  global scope, mm per minute

bool    isdigit (int a)
{
    if(a > ('0' - 1) && a < ('9' + 1))
        return  true;
    return  false;
}

bool    isupper (int a)
{
    if  ((a >= 'A') && (a <= 'Z'))  return  true;
    return  false;
}

int tolower (int a)
{
    if  (isupper(a))
        a += 'a' - 'A';
    return  a;
}

extern  double  find_distance (struct Gparams & from, struct Gparams & to, struct Gparams & distance);
extern  long    find_traverse_ticks(double dist, double feed_rate);
extern  struct  Gparams    last_position;

const int   goodcodes[] = {0,'a','b','c','i','j','l','r','x','y','z'};    //  possible G Code options
const int   const_numofcodes = sizeof(goodcodes) / sizeof(int);

int find_char_in_goodcodes  (int target)        //  Returns position of char in goodcodes[], 0 if not found.
{
    for (int i = 1; i < const_numofcodes; i++)
        if  (goodcodes[i] == target)
            return  i;
    return  0;
}

/*
void    get_codepositions   (struct singleGparam * a, struct Gparams & p)
    Only call from "void    g0g1cmdcore (struct singleGparam * a, double f_rate)"
Purpose:
    G code line may have any number of valid axes or parameters entered in any order or position.
    This function detects any X,Y,Z,A,I,J,R entries in 'p' if present and copies values into their
    respective positions within singleGparam 'a', setting the 'changed' flag for each to true if found,
    false if not found
struct  Gparams {  //  Where possibly messy G code line gets ordered and sorted into
    struct  singleGparam   x, y, z, i, j, r, a, b, c, d;   //  After sorting, know where to find any X, Y etc values !
}   ;
*/
void    get_codepositions   (struct singleGparam * source_array, struct Gparams & dest)
{
//const int   goodcodes[] = {0,'a','b','c','i','j','l','r','x','y','z'};    //  possible G Code options
//const int   const_numofcodes = sizeof(goodcodes) / sizeof(int);
    int         codecnt[const_numofcodes +1];
    int         codepos[const_numofcodes +1];
    int j;
    for (j = 0; j < const_numofcodes; j++)
        codecnt[j] = codepos[j] = 0;        //  Zero all results
    for (int i = 1; i <= source_array[0].i; i++)  {       //  for number of parameters passed to us here
        for(j = 0; j < const_numofcodes; j++)  {  //  for a, for b, ... for x, then y, then z
            if  (source_array[i].c == goodcodes[j])   {
                codecnt[j]++;   //  Count of number of 'a's, 'b's ... 'x's, 'y's, 'z's.  All should be 0 or 1 but could be more
                codepos[j] = i; //  Identifies the a[?] containing last incidence of goodcodes[j]
            }
        }
    }
    dest.x.changed = dest.y.changed = dest.z.changed = dest.a.changed = false;
    dest.i.changed = dest.j.changed = dest.r.changed = false;
    dest.x.dbl = last_position.x.dbl;   //  copy previous coordinates in case not re-specified
    dest.y.dbl = last_position.y.dbl;    dest.z.dbl = last_position.z.dbl;
    dest.a.dbl = last_position.a.dbl;    dest.i.dbl = last_position.i.dbl;
    dest.j.dbl = last_position.j.dbl;    dest.r.dbl = last_position.r.dbl;
    j = codepos[find_char_in_goodcodes('a')];
    if  (j)  {
        dest.a.changed = true;
        dest.a.dbl = source_array[j].dbl;
    }
    j = codepos[find_char_in_goodcodes('x')];
    if  (j)  {
        dest.x.changed = true;
        dest.x.dbl = source_array[j].dbl;
    }
    j = codepos[find_char_in_goodcodes('y')];
    if  (j)  {
        dest.y.changed = true;
        dest.y.dbl = source_array[j].dbl;
    }
    j = codepos[find_char_in_goodcodes('z')];
    if  (j)  {
        dest.z.changed = true;
        dest.z.dbl = source_array[j].dbl;
    }
    j = codepos[find_char_in_goodcodes('i')];
    if  (j)  {
        dest.i.changed = true;
        dest.i.dbl = source_array[j].dbl;
    }
    j = codepos[find_char_in_goodcodes('j')];
    if  (j)  {
        dest.j.changed = true;
        dest.j.dbl = source_array[j].dbl;
    }
    j = codepos[find_char_in_goodcodes('r')];
    if  (j)  {
        dest.r.changed = true;
        dest.r.dbl = source_array[j].dbl;
    }
}


void    g0g1cmdcore (struct singleGparam * source_array, double f_rate)    //  Updates any / all of x, y, z NCOs
{
    struct  Gparams                 pxyz, distance;
    struct  axis_speeds_element     q;
    get_codepositions   (source_array, pxyz);  //  will overwrite with new where entered
    pc.printf("g0");
    if  (pxyz.x.changed)  {pc.printf(" X %f", pxyz.x.dbl);}
    if  (pxyz.y.changed)  {pc.printf(" Y %f", pxyz.y.dbl);}
    if  (pxyz.z.changed)  {pc.printf(" Z %f", pxyz.z.dbl);}
    pc.printf("\r\n");
//    for (int j = 1; j < const_numofcodes; j++) {
//        pc.printf   ("Count of %c is %d, last position %d, last value %f\r\n", goodcodes[j], codecnt[j], codepos[j], a[codepos[j]].d);
//    }
    double  distT   = find_distance (last_position, pxyz, distance);  //  also fills in distance x y z
    double  temp    = n_for_onemmpermin * f_rate / distT;
    q.duration_ticks = find_traverse_ticks(distT, f_rate);
    last_position.x.dbl   = pxyz.x.dbl;     //  Update global last_position record
    last_position.y.dbl   = pxyz.y.dbl;
    last_position.z.dbl   = pxyz.z.dbl;
    q.x = (signed long)(temp * distance.x.dbl);
    q.y = (signed long)(temp * distance.y.dbl);
    q.z = (signed long)(temp * distance.z.dbl);
    q.a = 0;
    pir_updater (&q);     //    pir_updater (struct Gparams & p);   //  To arrive here with wanted 'mm per min' values in x, y and z
}

void    g0cmd (struct singleGparam * a)    //  Updates any / all of x, y, z NCOs
{
    g0g1cmdcore (a, feed_rate_max);     //  Defined parameter in code
}

void    g1cmd (struct singleGparam * a)    //  Updates any / all of x, y, z NCOs
{
    g0g1cmdcore (a, feed_rate);     //  Settable feed_rate
}

void    fcmd (struct singleGparam * a)   {
    if  (a[1].dbl < feed_rate_min || a[1].dbl > feed_rate_max)    {
        pc.printf   ("Errror setting feed rate, can't set to %f, ignoring request\r\n", a[1].dbl);
        return;
    }
    pc.printf   ("Setting feed_rate to %f\r\n", a[1].dbl);
    feed_rate = a[1].dbl;
}

extern unsigned long pir_s;
extern  int spindlefwdrev;

void    sfcmd (struct singleGparam * a)   {pc.printf("Spindle Fwd\r\n"); spindlefwdrev = 0;}
void    srcmd (struct singleGparam * a)   {pc.printf("Spindle Rev\r\n"); spindlefwdrev = 4;}
void    stopcmd (struct singleGparam * a)   {pc.printf("Stop ! er, not working yet\r\n");}

void    scmd (struct singleGparam * a)   {
    pc.printf("pir_s=0x%x\r\n", pir_s);
    if  (a[1].dbl < spindle_min || a[1].dbl > spindle_max)    {
        pc.printf   ("Errror setting spindle RPM, can't set to %f, ignoring request\r\n", a[1].dbl);
//        return;
    }
    pc.printf   ("Setting spindle RPM to %f\r\n", a[1].dbl);
//    feed_rate = a[1].d;   //  ****TO DO****
    pir_s = (unsigned long) (a[1].dbl * 4096);
    pc.printf("pir_s=0x%x\r\n", pir_s);
}

//void    stopcmd (struct grain * a)   {pc.printf("Stop !\r\n");}
void    m1cmd (struct singleGparam * a)   {pc.printf("m1 Optional Programme Stop\r\n");}
void    m3cmd (struct singleGparam * a)   {pc.printf("m3 Rotate Spindle Clockwise\r\n");}
void    m4cmd (struct singleGparam * a)   {pc.printf("m4 Rotate Spindle Counter Clockwise\r\n");}
void    m5cmd (struct singleGparam * a)   {pc.printf("m5 Stop Spindle\r\n");}
/*void    m30cmd (struct singleGparam * a)   {pc.printf("m30 Programme End and Rewind\r\n");}
void    m47cmd (struct singleGparam * a)   {pc.printf("m47 Repeat Prog from First Line\r\n");}
void    m48cmd (struct singleGparam * a)   {pc.printf("m48 Enable Speed and Feed Override\r\n");}
void    m49cmd (struct singleGparam * a)   {pc.printf("m49 Disable Speed and Feed Override\r\n");}
void    m98cmd (struct singleGparam * a)   {pc.printf("m98 Call Subroutine\r\n");}
void    m99cmd (struct singleGparam * a)   {pc.printf("m99 Return from Subroutine\r\n");}
void    g10cmd (struct singleGparam * a)   {pc.printf("g10 Coord System Origin Set\r\n");}
void    g17cmd (struct singleGparam * a)   {pc.printf("g17 XY Plane Select\r\n");}
void    g20cmd (struct singleGparam * a)   {pc.printf("g20 Inch\r\n");}
void    g21cmd (struct singleGparam * a)   {pc.printf("g21 mm\r\n");}

void    g40cmd (struct singleGparam * a)   {pc.printf("g40 Cutter Compensation Off\r\n");}
void    g50cmd (struct singleGparam * a)   {pc.printf("g50 Reset Scale Factors\r\n");}
void    g53cmd (struct singleGparam * a)   {pc.printf("g53 Move in Absolute Coordinates\r\n");}
void    g90cmd (struct singleGparam * a)   {pc.printf("g90 Absolute Distance Mode\r\n");}
*/
void    g2cmd (struct singleGparam * a)   {pc.printf("g2 Clockwise Arc\r\n");}
void    g3cmd (struct singleGparam * a)   {pc.printf("g3 CounterClockwise Arc\r\n");}
void    g4cmd (struct singleGparam * a)   {pc.printf("g4 Dwell\r\n");}
void    g91p1cmd (struct singleGparam * a)   {pc.printf("g91.1 \r\n");}

extern  struct  digital_readouts    dro;    //
void    drooncmd    (struct singleGparam * a)
{
    dro.dro_output = true;     //  Enable continuous dro display update
}
void    drooffcmd   (struct singleGparam * a)
{
    dro.dro_output = false;    //  Disable continuous dro display update
}

//extern  void    craptest    ()  ;
//void    g1cmd (struct singleGparam * a)   {
//    craptest    ();
//}

void    g90p1cmd (struct singleGparam * a)
{
    pc.printf   ("Arrived at function fredcmd with %d parameters\r\n", a[0].i);
    for (int i = 1; i <= a[0].i; i++)   {
        pc.printf   ("*%c* ", a[i].c);
        pc.printf   ("%d, ", a[i].i);
        pc.printf   ("%f\r\n", a[i].dbl);
    }
    pc.printf   (" endof param list\r\n");
}

void    menucmd (struct singleGparam * a);
struct  kb_command  {
    const char * cmd_word;         //  points to text e.g. "menu"
    const char * explan;
    void (*f)(struct singleGparam *);   //  points to function
}  kbc[] = {
    {(char const *)"menu", "Lists available commands, same as ls", menucmd},
    {(char const *)"ls", "Lists available commands, same as menu", menucmd},
    {"stop", "To Stop the Machine !", stopcmd},
    {"sf", "Spindle Clockwise", sfcmd},
    {"sr", "Spindle Anticlockwise", srcmd},
    {"f ", "To set Feed Rate mm/min, e.g. f 25", fcmd},
    {"s ", "To set Spindle RPM, e.g. S 1250", scmd},
    {"g0", "Not Implemented", g0cmd},
    /*{"m30", "Not Implemented", m30cmd},
    {"m47", "Not Implemented", m47cmd},
    {"m48", "Not Implemented", m48cmd},
    {"m49", "Not Implemented", m49cmd},
    {"m98", "Not Implemented", m98cmd},
    {"m99", "Not Implemented", m99cmd},
    {"m1", "Not Implemented", m1cmd},
    {"m3", "Not Implemented", m3cmd},
    {"m4", "Not Implemented", m4cmd},
    {"m5", "Not Implemented", m5cmd},
    {"g10", "Not Implemented", g10cmd},
    {"g17", "Not Implemented", g17cmd},
    {"g20", "Not Implemented", g20cmd},
    {"g21", "Not Implemented", g21cmd},
    {"g40", "Not Implemented", g40cmd},
    {"g50", "Not Implemented", g50cmd},
    {"g90.1", "Not Implemented", g90p1cmd},
    {"g91.1", "Not Implemented", g91p1cmd},
    {"g90", "Not Implemented", g90cmd},
    */
    {"g1", "", g1cmd},
    {"g2", "", g2cmd},
    {"g3", "", g3cmd},
    {"g4", "", g4cmd},
    {"dro on", "Turn dro readout on", drooncmd},
    {"dro off", "Turn dro readout off", drooffcmd}
};
const    int numof_menu_items = sizeof(kbc) / sizeof(kb_command);

void    menucmd (struct singleGparam * a)
{
    pc.printf("At menucmd function - listing commands:-\r\n");
    for(int i = 0; i < numof_menu_items; i++)
        pc.printf("[%s]\t\t%s\r\n", kbc[i].cmd_word, kbc[i].explan);
    pc.printf("End of List of Commands\r\n");
}

bool    isalpha (int c)
{
    if  ((c >= 'a') && (c <= 'z'))   return  true;
    if  ((c >= 'A') && (c <= 'Z'))   return  true;
    return  false;
}

char *  readout (char * txt, int p)         //  p has running subtotal of all pulses issued to stepper driver
{
    txt[0] = '+';               //  constructs string e.g. "+123.456"
    txt[8] = 0;                 //  null terminated
    if  (p < 0)    {
        txt[0] = '-';
        p = -p;
    }
    p *= 1000;
    p /= pulses_per_mm;
    for(int k = 7; k > 0; k--)  {
        if  (k == 4)
            txt[k] = '.';
        else    {
            txt[k] = '0' + (p % 10);
            p /= 10;
        }
    }
    return  txt;    //  Returns pointer unaltered for subsequent use by e.g. cout
}

////class CLI {

const int MAX_PARAMS = 20, MAX_CMD_LEN = 120;
char    cmd_line[MAX_CMD_LEN + 4];
struct  singleGparam   params[MAX_PARAMS + 1];
int     cl_index = 0, ch, lastalpha = 0;
double  fracmul;
/*
void    command_line_interpreter    ()
Purpose:

*/
void    command_line_interpreter    ()
{
    while  (pc.readable()) {
        if  (cl_index > MAX_CMD_LEN)  {   //  trap out stupidly long command lines
            pc.printf   ("Keyboard Error!! Killing stupidly long command line");
            cl_index = 0;
        }
        ch = tolower(pc.getc());
        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
            cmd_line[cl_index] = 0; //  null terminate command string
            if(cl_index)    {   //  If have got some chars to lookup
                int i, wrdlen;
                for (i = 0; i < numof_menu_items; i++)   {   //  Look for input match in command list
                    wrdlen = strlen(kbc[i].cmd_word);
                    if(strncmp(kbc[i].cmd_word, cmd_line, wrdlen) == 0)  {   //  If match found
                        bool negflag = false;
                        int state = 0, paramindex;
//                            pc.printf("Found match for word [%s]\r\n", kbc[i].wrd);
                        for(paramindex = 0; paramindex < MAX_PARAMS; paramindex++) {
                            // Clear out whole set of old parameters ready for anything new on this line
                            params[paramindex].i = 0;   //  for integer parameters
                            params[paramindex].c = 0;   //  for last alpha char, helps tie 'X' to '-23.5' etc
                            params[paramindex].dbl = 0.0; //  for floating point parameters
                            params[paramindex].ul = 0;
                            params[paramindex].changed = false;
                        }
                        paramindex = 0;
                        //  read any parameters from command line here
                        //  Using parameters[0] as count of parameters to follow
                        while   (wrdlen <= cl_index)  {
                            ch = cmd_line[wrdlen++];
                            if(isalpha(ch)) lastalpha = ch;
                            if(ch == '-')   negflag = true;
                            if(ch == '+')   negflag = false;
                            switch  (state) {
                                case    0:  //  looking for start of a number string
                                    if(isdigit(ch)) {   //  found first digit of a number string
                                        paramindex++;
                                        if(paramindex > MAX_PARAMS)    {
                                            wrdlen = cl_index;  //  exit condition
                                            pc.printf("WARNING - too many parameters, ignoring extra\r\n");
                                        } else    {
                                            params[paramindex].i = ch - '0';
                                            params[paramindex].c = lastalpha;
                                            state = 1;  //  Found first digit char of number string
                                        }
                                    }
                                    break;
                                case    1:  //  looking for end of a number string
                                    if(isdigit(ch)) {   //  accumulating integer from string
                                        params[paramindex].i *= 10;
                                        params[paramindex].i += ch - '0';
                                    } else    { //  found non-digit terminating number
                                        if  (ch == '.')  {
                                            state = 2;
                                            fracmul = 0.1;
                                            params[paramindex].dbl = (double)params[paramindex].i;
                                        } else    {
                                            params[0].i++;    //  count of validated parameters
                                            state = 0;  //  Have read past last digit of number string
                                            if(negflag) {
                                                params[paramindex].i = -params[paramindex].i;
                                                negflag = false;
                                            }
                                            params[paramindex].dbl = (double)params[paramindex].i;
                                        }
                                    }
                                    break;
                                case    2:  //  looking for fractional part of double
                                    if(isdigit(ch)) {   //  accumulating fractional part from string
                                        params[paramindex].dbl += (double)((ch - '0') * fracmul);
                                        fracmul /= 10.0;
                                    } else    { //  found non-digit terminating double precision number
                                        params[0].i++;    //  count of validated parameters
                                        state = 0;  //  Have read past last digit of number string
                                        if(negflag) {
                                            params[paramindex].i = -params[paramindex].i;
                                            params[paramindex].dbl = -params[paramindex].dbl;
                                            negflag = false;
                                        }
                                    }
                                    break;
                                default:
                                    break;
                            }   //  end of switch state
                        }       //  end of while wrdlen < cl_index
//                            pc.printf("Found match to [%s] with %d parameters\r\n", kbc[i].wrd, paramindex);
                        kbc[i].f(params);   //  execute command
                        i = numof_menu_items + 1;    //  to exit for loop
                    }
                }       // 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
            cl_index = lastalpha = 0;
        }               // End of else key was CR, may or may not be command to lookup
    }                   //  End of while (pc.readable())
//        osThreadYield();  //  Not using RTOS on this project
}

////} cli;