Shop OBEX P1 Docs P2 Docs Learn Events
GCC usage? - Page 2 — Parallax Forums

GCC usage?

24

Comments

  • ersmithersmith Posts: 6,053
    edited 2015-04-16 18:11
    OUCH, that is going to make using pointers to hub locations difficult.
    I presume you meant to say "pointers to cog locations will be difficult", since C pointers already point at hub memory. Yes, using pointers to cog memory is hard. That's why the C compiler doesn't support them -- indirect access to COG variables requires self modifying code, so you'll have to write a small piece of PASM to do it.
    So if I understand correctly for a COG only function and not using the stack I would do something like:
    _NATIVE MyFunc(a,b,c,d)
    char *c;
    {
      _COGMEM long tmp;
      /* Do something using int parameters a, b, and d, and string parameter c */
      return 0;
    }
    

    Yes, except that you probably have to declare local _COGMEM variables (inside functions) as "static", because that's how they will behave. A piece of COG memory will be permanently allocated for them.

    _NATIVE means to use the native COG jmpret calling convention (which is not standard compliant because it doesn't allow recursive functions). _COGMEM says to allocate the variable as a COG register.
  • ersmithersmith Posts: 6,053
    edited 2015-04-16 18:20
    "ANSI" style function prototypes (as used in K&R second edition!) have 2 big advantages over the old style function declarations:

    (1) They allow the compiler to check the types of parameters, and thus to catch typos and silly programming mistakes; and
    (2) Parameters do not have to be upconverted to the default types when passed to functions declared with prototypes.

    In
    float foo(x)
    float x;
    { return x; }
    ...
    float bar;
    foo(bar);
    
    The compiler has to convert bar from float to double, pass it in to function foo, and then convert it back to float there. If foo were declared as:
    float foo(float x)
    
    the parameter would stay a float the whole time. This is worst for float/double, but for shorts or chars there may also be some extraneous sign extensions.
  • davidsaundersdavidsaunders Posts: 1,559
    edited 2015-04-16 19:24
    idbruce wrote: »
    David

    All depending how deep you want to get into it.....

    The simpletools library (simpletools.h) is the goto place to get things done quickly and then other times, you may just need a Propeller function without all the extras, in which case just use propeller.h. To get your code size down to a minimum, check "Enable Pruning" under compiler options.

    Additionally, there are times when the SimpleIDE help is helpful for a quick reference, and then there are times when it is nice to look at the library itself, and the various definitions. Most if not all of the functions declared in simpletools.h, are defined in seperate C files. Although the C file names do not always match the function names. In which case, I simply search the function name, in the SimpleIDE directory, and several files usually pop up. Select the file that most closely resembles the function name and you will find the function defintion that you are seeking.
    Having looked at both simpletools,h and propeller.h, I will stick with propeller.h for sure (simple tools includes a lot of stuff that is useless to 99.9% of propeller programming).

    Thank you for the pointers on the sources of information.
  • davidsaundersdavidsaunders Posts: 1,559
    edited 2015-04-16 19:25
    If you need to see the definition of something in Simple, you can search the function name from PropWare's documentation site - Simple is documented there. For instance, by searching "putchar" in the top-right corner search box, I get this link. From there, you can see it says "Definition at line 11 of file putChar.c". Very helpful :)
    thank you for that.
  • Heater.Heater. Posts: 21,230
    edited 2015-04-16 19:28
    davidsaunders,
    How does the more readable form confuse people??
    Firstly it is debatable as to which style is more readable. Personally I think ANSI style is. And I of course started out in K&R days.

    Having the declaration in the header and the definition look the same is better.

    It allows the compiler to check the parameter types.

    It's will confuse because all other C code people will see is ANSI style.

    If you have "a good number of parameters" it's time to rethink your code.
  • davidsaundersdavidsaunders Posts: 1,559
    edited 2015-04-16 19:28
    ersmith wrote: »
    "ANSI" style function prototypes (as used in K&R second edition!) have 2 big advantages over the old style function declarations:

    (1) They allow the compiler to check the types of parameters, and thus to catch typos and silly programming mistakes; and
    (2) Parameters do not have to be upconverted to the default types when passed to functions declared with prototypes.

    In
    float foo(x)
    float x;
    { return x; }
    ...
    float bar;
    foo(bar);
    
    The compiler has to convert bar from float to double, pass it in to function foo, and then convert it back to float there. If foo were declared as:
    float foo(float x)
    
    the parameter would stay a float the whole time. This is worst for float/double, but for shorts or chars there may also be some extraneous sign extensions.
    Though with integers it is assumed to be int sized, the promotion is not an issue (just looked it up in the second edition C book), and as an int is 32 bits in size on the propeller that works perfectly. I can see the hassle if using LMM and passing a single character as a parameter.

    Besides how often do we all omit function prototypes when writing C programs, and it usually works out anyway :) .
  • Heater.Heater. Posts: 21,230
    edited 2015-04-16 19:43
    And int sized is what?

    Just do it the modern way.
  • davidsaundersdavidsaunders Posts: 1,559
    edited 2015-04-16 19:51
    Heater. wrote: »
    davidsaunders,

    Firstly it is debatable as to which style is more readable. Personally I think ANSI style is. And I of course started out in K&R days.

    Having the declaration in the header and the definition look the same is better.

    It allows the compiler to check the parameter types.

    It's will confuse because all other C code people will see is ANSI style.

    If you have "a good number of parameters" it's time to rethink your code.
    Well as I am attempting to make it easy to read for others, I guess that the ANSI style declarations are to be used. Well at least I do not have many functions (though I do admit to using goto in some of my C code for this project to save on functions in total).

    It is to bad that C no longer supports the entry keyword, many older C compilers used this to make multiple entry point functions possible, which any assembly coder can tell you is a good way to save code in many cases.
  • Heater.Heater. Posts: 21,230
    edited 2015-04-16 20:14
    The C language never supported the "entry" keyword. Thank God. Assembler programmers are free to use assembler.
  • SRLMSRLM Posts: 5,045
    edited 2015-04-16 20:27
    Well as I am attempting to make it easy to read for others, I guess that the ANSI style declarations are to be used. Well at least I do not have many functions (though I do admit to using goto in some of my C code for this project to save on functions in total).

    It is to bad that C no longer supports the entry keyword, many older C compilers used this to make multiple entry point functions possible, which any assembly coder can tell you is a good way to save code in many cases.

    All that may have been good when C was created and had poor compilers and lots of assembly programmer momentum. Newer versions of C, and even C++ are very efficient to the point where you don't need to and shouldn't try to get every last byte by weird code structure. Programming standards have evolved since then as well, with multiple entry points and GOTO being anti-patterns.
  • davidsaundersdavidsaunders Posts: 1,559
    edited 2015-04-16 20:28
    Heater. wrote: »
    The C language never supported the "entry" keyword. Thank God. Assembler programmers are free to use assembler.
    The first edition K&R C defined the entry keyword, though different compilers had quite different implementations (hence its being dropped in the second edition [and a not in the second edition about it being dropped]).

    Though some compilers implemented it quite well, some ignored it, and some did a poor job with it.
  • Heater.Heater. Posts: 21,230
    edited 2015-04-16 20:31
    As far as I recall "entry" was a reserved word. It was never defined in K&R.
  • davidsaundersdavidsaunders Posts: 1,559
    edited 2015-04-16 20:31
    SRLM wrote: »
    All that may have been good when C was created and had poor compilers and lots of assembly programmer momentum. Newer versions of C, and even C++ are very efficient to the point where you don't need to and shouldn't try to get every last byte by weird code structure. Programming standards have evolved since then as well, with multiple entry points and GOTO being anti-patterns.
    goto is generally bad, and I usually avoid it. Though multiple entry points can be shown to save code space in many many cases, do to the lack of needing some redundant code.

    As far as practices, modern programming practices seem to be waste as much RAM and CPU time as you can, and do as little as possible with it. That model does not do well with something like a low end MCU (like the Propeller), sorry.
  • davidsaundersdavidsaunders Posts: 1,559
    edited 2015-04-16 20:32
    Heater. wrote: »
    As far as I recall "entry" was a reserved word. It was never defined in K&R.
    That is correct, though it was often implemented. That is the reason for the inconsistent implementation of the entry keyword.
  • DavidZemonDavidZemon Posts: 2,973
    edited 2015-04-16 21:06
    You may want to take a look at the Simple, libpropeller and PropWare source code. They're all good examples of fast and efficient C and C++. And they dont use GOTO :)

    Where needed, you will find the occasional snippet of inline assembly.

    You'll even find you can use the awesomeness of C++ without increasing code size (and sometimes improving on it)
  • SRLMSRLM Posts: 5,045
    edited 2015-04-17 01:44
    As far as practices, modern programming practices seem to be waste as much RAM and CPU time as you can, and do as little as possible with it. That model does not do well with something like a low end MCU (like the Propeller), sorry.
    You may want to take a look at the Simple, libpropeller and PropWare source code. They're all good examples of fast and efficient C and C++. And they dont use GOTO :)

    Where needed, you will find the occasional snippet of inline assembly.

    You'll even find you can use the awesomeness of C++ without increasing code size (and sometimes improving on it)

    Thanks. You said exactly my point. Modern C++ can be efficient and lean, and without sacrificing for it.
  • davidsaundersdavidsaunders Posts: 1,559
    edited 2015-04-17 04:59
    On the use of goto:

    here is an example of my use of goto in the function I am working on at the moment:
    int GCode(void){
      char tc;
      short offset;
      offset = 0;
    
      for (offset= 0;codebuf[offset] <= 0x20;offset++); /*skip leading spaces.*/
    
      while codebuf[offset]){
        while (codebuf[offset++] <= 0x20); /*skip leading spaces.*/
        if ((codebuf[offset++] == 0xD) || (codebuf[offset++] == 0x0A))   /*checkj for end of line*/
          while (GCodePar.status);      /*Wait for command to finish running.*/
    
        tc = (2 | gcodebuf[offset++]); /*Upercase next character into tc.*/
        switch tc {
          case 'G':
            GetGParams(); ExecGCode(); break;
          case 'M':
            GetGParams(); ExecMCode(); break;
          default:
        }    
      }
      return 0;
    }
    
    you note the code near the end is a goto series selected with a switch statement. To save code I will continue that kind of thing.
  • DavidZemonDavidZemon Posts: 2,973
    edited 2015-04-17 05:08
    I'm confused... Are you referring to the cases within the switch as GOTOs? I get that they are functionally equivalent, but I don't think anyone refers to them as such. If that is the case, then its a huge sigh of relief as that is a very good use for them :)
  • TorTor Posts: 2,010
    edited 2015-04-17 05:12
    K&R declarations vs. ANSI declarations: The latter catches errors out of the box in a better way.
    static int k_r (a, b)
    int a;
    int b;
    {
            return (a + b);
    }
    
    static int ansi (int a, int b)
    {
            return (a + b);
    }
    
    int main (void)
    {
            int c = k_r (4, 5, 6);
            int d = ansi (4, 5, 6);
            
            return (0);
    }
    
    gcc -c ansi-vs-kr.c
    ansi-vs-kr.c: In function 'main':
    ansi-vs-kr.c:17:10: error: too many arguments to function 'ansi'
      int d = ansi (4, 5, 6);
              ^
    ansi-vs-kr.c:9:12: note: declared here
     static int ansi (int a, int b)
                ^
    
  • davidsaundersdavidsaunders Posts: 1,559
    edited 2015-04-17 05:16
    I'm confused... Are you referring to the cases within the switch as GOTOs? I get that they are functionally equivalent, but I don't think anyone refers to them as such. If that is the case, then its a huge sigh of relief as that is a very good use for them :)
    Well they are goto's, and the labels are the branch targets. It is actually a classic of the kind of goto you are supposed to avoid to prevent spaghetti code.
  • davidsaundersdavidsaunders Posts: 1,559
    edited 2015-04-17 05:18
    As I posted that function earlier today, as an example of how I use goto, here is the completed form of the function, please point out any error that I may have overlooked, and please point out anything that could be done more efficiently.
    /**************************************************************************
    * int GCode(void)                                                         *
    *                                                                         *
    * This function is the outer level of the simple G-Code parser.           *
    *                                                                         *
    * PARAMETERS:                                                             *
    * The contents of the character buffer, codebuf.                          *
    **************************************************************************/
    int GCode(void){
      char tc;
      short offset;
      offset = 0;
    
      while (codebuf[offset]){  /*Continue until next char is NULL.*/
        while (codebuf[offset++] <= 0x20); /*skip leading spaces.*/
        if ((codebuf[offset++] == 0xD) || (codebuf[offset++] == 0x0A))   /*checkj for end of line*/
          while (GCodePar.status);      /*Wait for command to finish running.*/
    
        tc = (2 | codebuf[offset++]); /*Upercase next character into tc.*/
        switch (tc) {                 /*Determine if we are using a G command or M command.*/
          case 'G':
            GetGParams(offset); ExecGCode(); break;
          case 'M':
            GetGParams(offset); ExecMCode(); break;
        }    
      }
      return 0;
    }
    
  • davidsaundersdavidsaunders Posts: 1,559
    edited 2015-04-17 05:22
    I just noticed an error in my code, here is the correction for the int GCode(void) function:
    /**************************************************************************
    * int GCode(void)                                                         *
    *                                                                         *
    * This function is the outer level of the simple G-Code parser.           *
    *                                                                         *
    * PARAMETERS:                                                             *
    * The contents of the character buffer, codebuf.                          *
    **************************************************************************/
    int GCode(void){
      char tc;
      short offset;
      offset = 0;
    
      while (codebuf[offset]){  /*Continue until next char is NULL.*/
        while (codebuf[offset++] <= 0x20); /*skip leading spaces.*/
        if ((codebuf[offset++] == 0xD) || (codebuf[offset++] == 0x0A))   /*checkj for end of line*/
          while (GCodePar.status);      /*Wait for command to finish running.*/
    
        tc = (2 | codebuf[offset++]); /*Upercase next character into tc.*/
        switch (tc) {                 /*Determine if we are using a G command or M command.*/
          case 'G':
            offset = GetGParams(offset); ExecGCode(); break;
          case 'M':
            offset = GetGParams(offset); ExecMCode(); break;
        }    
      }
      return 0;
    }
    
  • davidsaundersdavidsaunders Posts: 1,559
    edited 2015-04-17 05:55
    And here is a very bad example of using the switch case form of goto, this is from the function that I just wrote after finnishing the one posted above, so I have not yet got it commented:
    int GetGParams(long offset){
      char tstr[8] = {0,0,0,0,0,0,0,0};
      int  tmp;
      
      while (codebuf[offset] < 0x21) offset++; /*Skip spaces.*/
      while ((codebuf[offset] != 0x0D) && (codebuf[offset] != 0x0A)){
        switch (codebuf[offset++] | 2){
          case 'X':
            for (tmp = 0;(tstr[tmp] = codebuf[offset++]) > 0x2F && tmp < 0x3A;++tmp);
            GCodePar.x = str2inum(tstr);
            break;
          case 'Y':
            for (tmp = 0;(tstr[tmp] = codebuf[offset++]) > 0x2F && tmp < 0x3A;++tmp);
            GCodePar.y = str2inum(tstr);
            break;
          case 'Z':
            for (tmp = 0;(tstr[tmp] = codebuf[offset++]) > 0x2F && tmp < 0x3A;++tmp);
            GCodePar.z = str2inum(tstr);
            break;
          case 'E':
            for (tmp = 0;(tstr[tmp] = codebuf[offset++]) > 0x2F && tmp < 0x3A;++tmp);
            GCodePar.e = str2inum(tstr);
            break;
          case 'F':
            for (tmp = 0;(tstr[tmp] = codebuf[offset++]) > 0x2F && tmp < 0x3A;++tmp);
            GCodePar.x = str2inum(tstr);
            break;
          case 'P':
            for (tmp = 0;(tstr[tmp] = codebuf[offset++]) > 0x2F && tmp < 0x3A;++tmp);
            GCodePar.f = str2inum(tstr);
            break;
          case 'S':
            for (tmp = 0;(tstr[tmp] = codebuf[offset++]) > 0x2F && tmp < 0x3A;++tmp);
            GCodePar.s = str2inum(tstr);
            break;
        }      
      }  
    


    Commenting code completely is somewhat difficult, as for me the above is well enough commented to read even 6 months down the road, though that is not the case for most people.
  • Dave HeinDave Hein Posts: 6,347
    edited 2015-04-17 06:10
    The line "switch (codebuf[offset++] | 2){" doesn't look right. You are OR'ing a 1 into the second least significant bit. Only the letters 'Z' and 'F' have this bit set, so all the other cases would never happen. I don't understand why you include the "| 2" in the switch statement. Also, you may want to have a default case to catch anything that doesn't match one of the other cases.
  • davidsaundersdavidsaunders Posts: 1,559
    edited 2015-04-17 09:15
    Dave Hein wrote: »
    The line "switch (codebuf[offset++] | 2){" doesn't look right. You are OR'ing a 1 into the second least significant bit. Only the letters 'Z' and 'F' have this bit set, so all the other cases would never happen. I don't understand why you include the "| 2" in the switch statement. Also, you may want to have a default case to catch anything that doesn't match one of the other cases.
    That is an error on my part, it should read:
    switch (codebuf[offset++] | 0x20){
    That does a toupper operation and uses only the upper case characters.
  • davidsaundersdavidsaunders Posts: 1,559
    edited 2015-04-17 09:20
    Dave Hein wrote: »
    The line "switch (codebuf[offset++] | 2){" doesn't look right. You are OR'ing a 1 into the second least significant bit. Only the letters 'Z' and 'F' have this bit set, so all the other cases would never happen. I don't understand why you include the "| 2" in the switch statement. Also, you may want to have a default case to catch anything that doesn't match one of the other cases.
    Perhaps this looks better:
    /**************************************************************************
    **************************************************************************/
    int GetGParams(long offset){
      char tstr[8] = {0,0,0,0,0,0,0,0};
      int  tmp;
      
      while (codebuf[offset] < 0x21) offset++; /*Skip spaces.*/
      while ((codebuf[offset] != 0x0D) && (codebuf[offset] != 0x0A) && codebuf[offset]){
        switch (codebuf[offset++] | 0x20){
          case 'X':
            for (tmp = 0;(tstr[tmp] = codebuf[offset++]) > 0x2F && tmp < 0x3A;++tmp);
            GCodePar.x = str2inum(tstr);
            break;
          case 'Y':
            for (tmp = 0;(tstr[tmp] = codebuf[offset++]) > 0x2F && tmp < 0x3A;++tmp);
            GCodePar.y = str2inum(tstr);
            break;
          case 'Z':
            for (tmp = 0;(tstr[tmp] = codebuf[offset++]) > 0x2F && tmp < 0x3A;++tmp);
            GCodePar.z = str2inum(tstr);
            break;
          case 'E':
            for (tmp = 0;(tstr[tmp] = codebuf[offset++]) > 0x2F && tmp < 0x3A;++tmp);
            GCodePar.e = str2inum(tstr);
            break;
          case 'F':
            for (tmp = 0;(tstr[tmp] = codebuf[offset++]) > 0x2F && tmp < 0x3A;++tmp);
            GCodePar.f = str2inum(tstr);
            break;
          case 'P':
            for (tmp = 0;(tstr[tmp] = codebuf[offset++]) > 0x2F && tmp < 0x3A;++tmp);
            GCodePar.p = str2inum(tstr);
            break;
          case 'S':
            for (tmp = 0;(tstr[tmp] = codebuf[offset++]) > 0x2F && tmp < 0x3A;++tmp);
            GCodePar.s = str2inum(tstr);
            break;
        }      
      }  
      
      return offset;
    }
    

    and this:
    /**************************************************************************
    * int GCode(void)                                                         *
    *                                                                         *
    * This function is the outer level of the simple G-Code parser.           *
    *                                                                         *
    * PARAMETERS:                                                             *
    * The contents of the character buffer, codebuf.                          *
    **************************************************************************/
    int GCode(void){
      char tc;
      short offset;
      offset = 0;
    
      while (codebuf[offset]){  /*Continue until next char is NULL.*/
        while (codebuf[offset] < 0x21) offset++; /*skip leading spaces.*/
        if ((codebuf[offset++] == 0xD) || (codebuf[offset++] == 0x0A))   /*checkj for end of line*/
          while (GCodePar.status);      /*Wait for command to finish running.*/
    
        switch (codebuf[offset++] | 0x20) {                 /*Determine if we are using a G command or M command.*/
          case 'G':
            offset = GetGParams(offset); ExecGCode(); break;
          case 'M':
            offset = GetGParams(offset); ExecMCode(); break;
        }    
      }
      return 0;
    }
    

    I do thank you for noticing that error, I was half asleep when I wrote those this morning, and that error would have gone unnoticed for a while.

    Though as seen I have corrected those.

    Please if you notice any other errors in my code do point them out, I will be posting a lot soon (will be in a new thread), so second sets of eyes help.
  • Dave HeinDave Hein Posts: 6,347
    edited 2015-04-17 09:48
    Actually you are doing a quick and dirty implementation of tolower(). If you want to convert to uppercase you need to do "& (~0x20)". Or you can do "| 0x20" and change the values in your case statements to lower case.
  • davidsaundersdavidsaunders Posts: 1,559
    edited 2015-04-17 09:49
    Dave Hein wrote: »
    Actually you are doing a quick and dirty implementation of tolower(). If you want to convert to uppercase you need to do "& (~0x20)". Or you can do "| 0x20" and change the values in your case statements to lower case.
    Thank you I always get that backwards.
  • davidsaundersdavidsaunders Posts: 1,559
    edited 2015-04-17 09:53
    Dave Hein wrote: »
    Actually you are doing a quick and dirty implementation of tolower(). If you want to convert to uppercase you need to do "& (~0x20)". Or you can do "| 0x20" and change the values in your case statements to lower case.

    Does this look better? :
    /**************************************************************************
    * int GetGParams(long offset)                                             *
    *                                                                         *
    * Parses the G-Code parameter string and fills in the GCodePar struct for *
    * this command.                                                           *
    *                                                                         *
    * PARAMETERS:                                                             *
    * long offset : The offset in the codebuf buffer where the parameters     *
    *               begin                                                     *
    *                                                                         *
    * RETURNS:                                                                *
    *   The offset in the G-Code buffer after the end of the parameters.      *
    *                                                                         *
    * TODO:                                                                   *
    *   DONE: Add the ability to skip past comments at the end of line.       *
    **************************************************************************/
    int GetGParams(long offset){
      char tstr[8] = {0,0,0,0,0,0,0,0};
      int  tmp;
      
      while (codebuf[offset] < 0x21) offset++; /*Skip spaces.*/
      while ((codebuf[offset] != 0x0D) && (codebuf[offset] != 0x0A) && codebuf[offset]){
        switch (codebuf[offset++] | 0x20){
          case 'x':
            for (tmp = 0;(tstr[tmp] = codebuf[offset++]) > 0x2F && tmp < 0x3A;++tmp);
            GCodePar.x = str2inum(tstr);
            break;
          case 'y':
            for (tmp = 0;(tstr[tmp] = codebuf[offset++]) > 0x2F && tmp < 0x3A;++tmp);
            GCodePar.y = str2inum(tstr);
            break;
          case 'z':
            for (tmp = 0;(tstr[tmp] = codebuf[offset++]) > 0x2F && tmp < 0x3A;++tmp);
            GCodePar.z = str2inum(tstr);
            break;
          case 'e':
            for (tmp = 0;(tstr[tmp] = codebuf[offset++]) > 0x2F && tmp < 0x3A;++tmp);
            GCodePar.e = str2inum(tstr);
            break;
          case 'f':
            for (tmp = 0;(tstr[tmp] = codebuf[offset++]) > 0x2F && tmp < 0x3A;++tmp);
            GCodePar.f = str2inum(tstr);
            break;
          case 'p':
            for (tmp = 0;(tstr[tmp] = codebuf[offset++]) > 0x2F && tmp < 0x3A;++tmp);
            GCodePar.p = str2inum(tstr);
            break;
          case 's':
            for (tmp = 0;(tstr[tmp] = codebuf[offset++]) > 0x2F && tmp < 0x3A;++tmp);
            GCodePar.s = str2inum(tstr);
            break;
          case ';':
            while (codebuf[offset] != 0x0A && codebuf[offset] != 0x0D) ++offset;
        }      
      }  
      
      return offset;
    }
    

    And:
    /**************************************************************************
    * int GCode(void)                                                         *
    *                                                                         *
    * This function is the outer level of the simple G-Code parser.           *
    *                                                                         *
    * PARAMETERS:                                                             *
    * The contents of the character buffer, codebuf.                          *
    *                                                                         *
    * TODO:                                                                   *
    *   DONE: Add the ability to skip past comments at the end of line.       *
    **************************************************************************/
    int GCode(void){
      char tc;
      short offset;
      offset = 0;
    
      while (codebuf[offset]){  /*Continue until next char is NULL.*/
        while (codebuf[offset] < 0x21) offset++; /*skip leading spaces.*/
        if ((codebuf[offset++] == 0xD) || (codebuf[offset++] == 0x0A))   /*checkj for end of line*/
          while (GCodePar.status);      /*Wait for command to finish running.*/
    
        switch (codebuf[offset++] | 0x20) {                 /*Determine if we are using a G command or M command.*/
          case 'g':
            offset = GetGParams(offset); ExecGCode(); break;
          case 'm':
            offset = GetGParams(offset); ExecMCode(); break;
          case ';':
            while (codebuf[offset] != 0x0A && codebuf[offset] != 0x0D) ++offset;
        }    
      }
      return 0;
    }
    

    Thank you again.
  • Dave HeinDave Hein Posts: 6,347
    edited 2015-04-17 10:38
    It looks OK, except there's some ambiguity about the ';' character. An ESCAPE character (0x1b) would be mapped to a semicolon (0x3b). As long as your string doesn't contain an ESCAPE character you should be OK.
Sign In or Register to comment.