Quadrature encoder mode Teensy 4.1

Steve_AU

Member
Hi all,
Very new here.
As a hobbyist stretching back to the 80's, I have dealt with EPROM erasers, ZIF sockets and lines of EPROMS. I have sat there gobsmacked at processors like Z80/NSC800, 8085 SDK from Intel, built a bunch of 8051 and Phillips automotive derivatives - PCB80C552 - plus dabbled with the 6809 and the Texas TMS320C325/6 and Motorola DSP56002 hosted in a PC ISA bus (old type).

More recently (2009) have had my heart set on the Microchip PIC32 until I discovered the STM32 range, Cube-MX and Cube-IDE and then found the Teensy4.1 on a YouTube video. The guy raved about it.

Now I have ordered several from this site, and I have my hands on one that I bought locally in AU to do some initial playing. Out of the box, it can toggle a pin at 10Mhz

The development of embedded systems in 40 years has been amazing. The effort put into the tooling is stunning and so affordable (almost nothing).

Teensy4.1 made me get into the Arduino IDE, and that's where I am now - beginning again.

At last, the question.
My question is related to using the quadrature encoder hardware in Teensy4.1. Many STM32 breeds have an 'encoder mode' which was deceptively easy to enable (in Cube-MX), and it worked - great fun, especially with the use of a 32-bit counter (TIM2 on the STM32F401 etc.). My search on the Arduino libraries under Teensy has a couple of quadrature encoder/decoder examples based on interrupts and phase detection logic. What I wanted to ask is where I can find some examples or documentation on setting up Teensy4.1 counter hardware in encoder mode, run-able from the Arduino IDE? It looks like there are up to 4 of these quadrature-capable counters.

(I got there in the end)
Steve
 
Thanks, BriComp,
I had a scan just now. My intuition is that each channel only has 16-bit timers for this function. In the early days, I fiddled with the 16-bit encoder mode counters on the STM32 series, trying to catch the overflow on each encoder rotation or 16-bit count, until I found the 32-bit timer (TIM2), which made it so easy.
With 5 micron resolution and 32 bits on my (milling machine) linear scale, I could theoretically measure 21 kilometres of linear motion. With 16 bits, every 341 mm, I'd have to bump a counter variable to keep track of the count at the same time as keeping note of the direction. It was doable if untidy (I never really liked what I had done). A 32-bit timer makes the problem go away. Meantime, the Teensy4.1 processor is so attractive. What a time to be alive... :)
Steve
 
Some more info for you @Clinker8 has fully instrumented his lathe using Teensy. You can see some of his entries starting in this stream.

EDIT: I think @Luni has expanded his library (or can be expanded) to give int64 output.
 
Last edited:
Some more info for you @Clinker8 has fully instrumented his lathe using Teensy. You can see some of his entries starting in this stream.

EDIT: I think @Luni has expanded his library (or can be expanded) to give int64 output.

Thanks for the link(s)! I'll have an in-depth read. There's a lot more goodness in there than just the encoder material, at a cursory glance.

Kind regards,
Steve
 
Thanks for the link(s)! I'll have an in-depth read. There's a lot more goodness in there than just the encoder material, at a cursory glance.

Kind regards,
Steve

Yes, I am using int64 counters for my electronic lead screw in my lathe. @luni was gracious (and talented enough) to modify his encoder library. I can report it is working well on two different lathes. I am also using the same library to read standard glass or magnetic scales for position. My ELS is not intended to be a CNC, but merely a means to eliminate gear changing. I do intend to upgrade its features, which is a work in progress. The Teensy has been a dream to work with, and this forum has been very helpful. If you have questions, don't hesitate to ask. Can't guarantee I will know the answer, but it is likely someone else might.
 
Yes, I am using int64 counters for my electronic lead screw in my lathe. @luni was gracious (and talented enough) to modify his encoder library. I can report it is working well on two different lathes. I am also using the same library to read standard glass or magnetic scales for position. My ELS is not intended to be a CNC, but merely a means to eliminate gear changing. I do intend to upgrade its features, which is a work in progress. The Teensy has been a dream to work with, and this forum has been very helpful. If you have questions, don't hesitate to ask. Can't guarantee I will know the answer, but it is likely someone else might.

Beautiful stuff! I'll be surely taking you up on that. I have to go away on work-related tasks for a few days, so I'll be offline for a bit.

My first desire is to measure scales reliably (I have a VEVOR DRO and such, but that's just the start) |My real thinking is to converge on a CNC-type function (I had a go at this back in 1991 with far less capable tools). I have a G-Code parser and such that I have written for the STM32 series (well, it started life on a Z80). Lots of bits and pieces that need to be converged and too many rabbit holes that beckon.

I can't help myself with the Teensy4.1. Just have to look at it and get the feel of it. So much fun stuff - e.g. link the indexing head with the milling machine for gear cutting and possibly have an electronic feed screw on the lathe for thread cutting as you have. Maybe built a router..... Way too many ideas, and not enough life to do them all.

Steve
 
Beautiful stuff! I'll be surely taking you up on that. I have to go away on work-related tasks for a few days, so I'll be offline for a bit.

My first desire is to measure scales reliably (I have a VEVOR DRO and such, but that's just the start) |My real thinking is to converge on a CNC-type function (I had a go at this back in 1991 with far less capable tools). I have a G-Code parser and such that I have written for the STM32 series (well, it started life on a Z80). Lots of bits and pieces that need to be converged and too many rabbit holes that beckon.

I can't help myself with the Teensy4.1. Just have to look at it and get the feel of it. So much fun stuff - e.g. link the indexing head with the milling machine for gear cutting and possibly have an electronic feed screw on the lathe for thread cutting as you have. Maybe built a router..... Way too many ideas, and not enough life to do them all.

Steve

Scales are easy. I was surprised at how well it seemed to work. A scale is merely a linear quadrature encoder. Just count pulses and multiply the count by your calibration factor. Oh, and check for double counts and stuff like that. About 30 LOC with lots of blank lines, for an axis. When you get back I can give you a simple example.
 
Hi Clinker8,
I'm back from the trip away and spending some time porting some of my code across the Teensy4.1. I wondered if it is possible to get access to the actual interrupt handler attached to Serial1?

From what I can see, the interrupt and buffering of same, is hidden. Each call to serial1Event() to check on the availability of characters effectively polls the state of the buffer from the main loop. I want to fill my own circular buffer from the incoming interrupt as I did on the STM32. Is there any more information at that level that you know about?

I do have a workable sequence running on Teensy4.1, but if there is too much idle time in the main loop, [like pulsing a led for 50mS], it doesn't work predictably.

I'd like to emulate what I have done on the other processors if I can OR understand the FIFO/interrupt workings in the Arduino code much better.

In my other code, the main loop can be blocked indefinitely, while the interrupt fills up the buffer and a 'buffer_count()' function which runs on each char interrupt de-asserts RTS, telling the host to stop at a defined char count. In this case on Teensy, if the main loop blocks, it doesn't work as I might hope.
Stevo
 
I decided to let Teensy manage RTS. That seems to have fixed the blocking problems and I'll just rearrange things to deal with it that way for now.
Stevo
 
Hi Clinker8,
I'm back from the trip away and spending some time porting some of my code across the Teensy4.1. I wondered if it is possible to get access to the actual interrupt handler attached to Serial1?

From what I can see, the interrupt and buffering of same, is hidden. Each call to serial1Event() to check on the availability of characters effectively polls the state of the buffer from the main loop. I want to fill my own circular buffer from the incoming interrupt as I did on the STM32. Is there any more information at that level that you know about?

I do have a workable sequence running on Teensy4.1, but if there is too much idle time in the main loop, [like pulsing a led for 50mS], it doesn't work predictably.

I'd like to emulate what I have done on the other processors if I can OR understand the FIFO/interrupt workings in the Arduino code much better.

In my other code, the main loop can be blocked indefinitely, while the interrupt fills up the buffer and a 'buffer_count()' function which runs on each char interrupt de-asserts RTS, telling the host to stop at a defined char count. In this case on Teensy, if the main loop blocks, it doesn't work as I might hope.
Stevo

I'm afraid, I'm not following you. I'm directly counting encoder pulses, via the library, and not doing anything with Serial1. Since you haven't posted any code, both me and the rest of the forum can only guess at what you are doing. Pulsing a LED using the delay function is not good, you may know that. At the top of the page is a Rule, perhaps you missed it.

Forum Rule: Always post complete source code & details to reproduce any issue!

That being said, I have been guilty of not providing source code at times. Either the attachment is too large, or proprietary, or I don't have permission to post it. But I do try to post pertinent bits, and when I can, complete sections of a problem area. It could be something in your setup, or a misunderstanding of how something does work, but we won't know about it, unless you post the code. Generally speaking, using Serial.printx inside an interrupt is bad news. Sometimes you can get away with it - but most of the time it is the recipe for disaster... As for FIFOs, I will let other members comment, as they are far better coders than I am. I know why they are good, and I have designed systems with them, but nothing to do with a Teensy.
 
Hi Clinker8,
Sorry about the vagueness. I'm dealing with the porting of some already-written code. This is not about encoders or really about an 'issue'. Perhaps I should have begun another thread! It's more about understanding how Teensy deals with serial data incoming and the way Teensy Serial (UART) handlers are written. So it's not even about an issue particularly, it's about understanding the serial port buffering.

The pertinent code is post-able, but that's not my worry, as I have it all working. The call to 'Serial1Event' now happens at the top of the loop. The blipping of the led is in the main loop, not in an interrupt. (Yes, I realise interrupts are to be exited ASAP!)

My interest is how the serial port (UART) interrupt and FIFO buffering is being managed (out of sight to me).
I'll post my code here anyway so you can see what is.

The first lot is to just expose the loop and the call to serial1event() just to shine a light on that part.

The rest is a port of the code as it stands so far, for context.

What I would love to do is set out each module into a separate file. Can't see how to do that with Arduino IDE. (yet) VSCode and PlatformIO might be a better way.
Kind regards,
Stevo

Code:
[COLOR=#000000][FONT=Consolas][COLOR=#008000]//------------------------------------------------------------------------------[/COLOR]
[COLOR=#008000]// local module variables[/COLOR]
[COLOR=#008000]//------------------------------------------------------------------------------[/COLOR]
[COLOR=#0000FF]int[/COLOR] LED = [COLOR=#098658]13[/COLOR];[COLOR=#008000]  // pin 13 is the orange LED[/COLOR]
[COLOR=#0000FF]char[/COLOR] [COLOR=#001080]block[/COLOR][[COLOR=#098658]256[/COLOR]];
[COLOR=#0000FF]char[/COLOR] [COLOR=#001080]cmdln[/COLOR][[COLOR=#098658]256[/COLOR]];
[COLOR=#008000]//------------------------------------------------------------------------------[/COLOR]
[COLOR=#008000]// kick-off code[/COLOR]
[COLOR=#008000]//------------------------------------------------------------------------------[/COLOR]
[COLOR=#0000FF]void[/COLOR] [COLOR=#795E26]setup[/COLOR]() {
  [COLOR=#795E26]pinMode[/COLOR](LED, OUTPUT);
  [COLOR=#001080]Serial[/COLOR].[COLOR=#795E26]begin[/COLOR]([COLOR=#098658]115200[/COLOR]);
  [COLOR=#001080]Serial1[/COLOR].[COLOR=#795E26]begin[/COLOR]([COLOR=#098658]115200[/COLOR], SERIAL_8N1);
  [COLOR=#001080]Serial1[/COLOR].[COLOR=#795E26]setRX[/COLOR]([COLOR=#098658]0[/COLOR]);
  [COLOR=#001080]Serial1[/COLOR].[COLOR=#795E26]setTX[/COLOR]([COLOR=#098658]1[/COLOR]);
  [COLOR=#001080]Serial1[/COLOR].[COLOR=#795E26]attachRts[/COLOR]([COLOR=#098658]2[/COLOR]);
  [COLOR=#795E26]event_queue_init[/COLOR]();[COLOR=#008000] // setup an event queue[/COLOR]
  [COLOR=#795E26]machine_init[/COLOR]();[COLOR=#008000]    // initliase the machine with 3 axes.[/COLOR]
}
[COLOR=#008000]//------------------------------------------------------------------------------[/COLOR]
[COLOR=#008000]// main loop()[/COLOR]
[COLOR=#008000]//------------------------------------------------------------------------------[/COLOR]
[COLOR=#0000FF]void[/COLOR] [COLOR=#795E26]loop[/COLOR]() {
  [COLOR=#795E26]serial1Event[/COLOR]();[COLOR=#008000]         // check for the arrival of any chars[/COLOR]
  [COLOR=#AF00DB]if[/COLOR] (line_count) {[COLOR=#008000]       // if we have a new line of chars terminated by CRLF[/COLOR]
    [COLOR=#795E26]buff_read[/COLOR](cmdln);[COLOR=#008000]     // read them out of the cirular buffer into a null terminated linear char array[/COLOR]
    [COLOR=#795E26]parse_command[/COLOR](cmdln);[COLOR=#008000] // parse this into commands data and hash [/COLOR]
    [COLOR=#795E26]blip_led[/COLOR]([COLOR=#098658]100[/COLOR]);[COLOR=#008000]        // this emulates a time delay/wait on the machine function (100us)[/COLOR]
  }
}
1200 more lines
...[/FONT][/COLOR]
Code:
[COLOR=#AF00DB][FONT=Consolas]#include[/FONT][/COLOR][COLOR=#A31515][FONT=Consolas]<TeensyThreads.h>[/FONT][/COLOR][COLOR=#000000][FONT=Consolas][COLOR=#af00db]#include[/COLOR][COLOR=#a31515]<errno.h>[/COLOR]
[COLOR=#008000]//----------------------------------------------------------------------------[/COLOR]
[COLOR=#008000]// message_32 defines[/COLOR]
[COLOR=#008000]//----------------------------------------------------------------------------[/COLOR]
[COLOR=#af00db]#define[/COLOR][COLOR=#0000ff] MESSAGE_ERROR_DESC_LENGTH [/COLOR][COLOR=#098658]32[/COLOR]
[COLOR=#af00db]#define[/COLOR][COLOR=#0000ff] MAX_XML_TAG [/COLOR][COLOR=#098658]16[/COLOR][COLOR=#008000]                  // 16 chars of XML tag (keep them short!!)[/COLOR]
[COLOR=#af00db]#define[/COLOR][COLOR=#0000ff] COMMAND_LINE_LENGTH [/COLOR][COLOR=#098658]256[/COLOR][COLOR=#008000]         // maximum value of a line including terminator chars[/COLOR]
[COLOR=#af00db]#define[/COLOR][COLOR=#0000ff] UART_BUFFER_SIZE [/COLOR][COLOR=#098658]1024[/COLOR][COLOR=#008000]           // max circular buffer[/COLOR]
[COLOR=#af00db]#define[/COLOR][COLOR=#0000ff] CHAR_COUNT_LOWER_THRESHOLD [/COLOR][COLOR=#098658]256[/COLOR][COLOR=#008000]  //[/COLOR]
[COLOR=#af00db]#define[/COLOR][COLOR=#0000ff] CHAR_COUNT_UPPER_THRESHOLD [/COLOR][COLOR=#098658]768[/COLOR][COLOR=#008000]  //[/COLOR]
[COLOR=#008000]// gc_parser defines[/COLOR]
[COLOR=#af00db]#define[/COLOR][COLOR=#0000ff] MAX_ARGS [/COLOR][COLOR=#098658]32[/COLOR]
[COLOR=#af00db]#define[/COLOR][COLOR=#0000ff] COMMAND_LENGTH [/COLOR][COLOR=#098658]256[/COLOR]
[COLOR=#af00db]#define[/COLOR][COLOR=#0000ff] COMMENT_LENGTH [/COLOR][COLOR=#098658]128[/COLOR]
[COLOR=#af00db]#define[/COLOR][COLOR=#0000ff] ERROR_DESC_LENGTH [/COLOR][COLOR=#098658]64[/COLOR]
[COLOR=#008000]// event_queue defines[/COLOR]
[COLOR=#af00db]#define[/COLOR][COLOR=#0000ff] MAX_EVENT_QUEUE [/COLOR][COLOR=#098658]64[/COLOR][COLOR=#008000]                                    // up to 64 events in a queue[/COLOR]
[COLOR=#af00db]#define[/COLOR][COLOR=#0000ff] UPPER_EVENT_BUFFER_THRESHOLD [/COLOR][COLOR=#098658]3[/COLOR]*[COLOR=#0000ff] MAX_EVENT_QUEUE [/COLOR]/[COLOR=#098658]4[/COLOR][COLOR=#008000]  // set 'full' above this threshold[/COLOR]
[COLOR=#af00db]#define[/COLOR][COLOR=#0000ff] LOWER_EVENT_BUFFER_THRESHOLD MAX_EVENT_QUEUE [/COLOR]/[COLOR=#098658]4[/COLOR][COLOR=#008000]      // reset 'full' below this threshold[/COLOR]
[COLOR=#af00db]#define[/COLOR][COLOR=#0000ff] MAX_EVENT_PARAMS [/COLOR][COLOR=#098658]3[/COLOR][COLOR=#008000]                                    // up to 3 integer parameters per event[/COLOR]
[COLOR=#af00db]#define[/COLOR][COLOR=#0000ff] MAX_EVENT_ID [/COLOR][COLOR=#098658]16[/COLOR][COLOR=#008000]                                       // 16 chars in an event id[/COLOR]
[COLOR=#af00db]#define[/COLOR][COLOR=#0000ff] MAX_COEFFS [/COLOR][COLOR=#098658]3[/COLOR]
[COLOR=#af00db]#define[/COLOR][COLOR=#0000ff] MAX_WORLDS [/COLOR][COLOR=#098658]16[/COLOR]
[COLOR=#af00db]#define[/COLOR][COLOR=#0000ff] NAME_WIDTH [/COLOR][COLOR=#098658]16[/COLOR]
[COLOR=#af00db]#define[/COLOR][COLOR=#0000ff] GC_PER_BLOCK [/COLOR][COLOR=#098658]4[/COLOR]
[COLOR=#af00db]#define[/COLOR][COLOR=#0000ff] MC_PER_BLOCK [/COLOR][COLOR=#098658]4[/COLOR]

[COLOR=#af00db]#define[/COLOR][COLOR=#0000ff] MESSAGE_ERROR_DESC_LENGTH [/COLOR][COLOR=#098658]32[/COLOR]
[COLOR=#af00db]#define[/COLOR][COLOR=#0000ff] TRUE [/COLOR]-[COLOR=#098658]1[/COLOR]
[COLOR=#af00db]#define[/COLOR][COLOR=#0000ff] FALSE [/COLOR][COLOR=#098658]0[/COLOR]
[COLOR=#af00db]#define[/COLOR][COLOR=#0000ff] MAX_XML_TAG [/COLOR][COLOR=#098658]16[/COLOR][COLOR=#008000]  // 16 chars of XML tag (keep them short!!)[/COLOR]

[COLOR=#008000]//---------------------------------------------------------------------------------------[/COLOR]
[COLOR=#008000]// cmd formats[/COLOR]
[COLOR=#af00db]#define[/COLOR][COLOR=#0000ff] GET_MOVE [/COLOR][COLOR=#098658]10[/COLOR]
[COLOR=#af00db]#define[/COLOR][COLOR=#0000ff] GET_MODE_BITS [/COLOR][COLOR=#098658]11[/COLOR]
[COLOR=#af00db]#define[/COLOR][COLOR=#0000ff] GET_PID [/COLOR][COLOR=#098658]14[/COLOR]
[COLOR=#af00db]#define[/COLOR][COLOR=#0000ff] GET_ANALOG [/COLOR][COLOR=#098658]15[/COLOR]
[COLOR=#af00db]#define[/COLOR][COLOR=#0000ff] GET_PORT [/COLOR][COLOR=#098658]17[/COLOR]
[COLOR=#af00db]#define[/COLOR][COLOR=#0000ff] GET_ENCODER_POS [/COLOR][COLOR=#098658]19[/COLOR]
[COLOR=#af00db]#define[/COLOR][COLOR=#0000ff] GET_ENCODER_CNT [/COLOR][COLOR=#098658]20[/COLOR]
[COLOR=#008000]//[/COLOR]
[COLOR=#af00db]#define[/COLOR][COLOR=#0000ff] GET_FLOW_CONTROL_STATE [/COLOR][COLOR=#098658]0[/COLOR]
[COLOR=#af00db]#define[/COLOR][COLOR=#0000ff] GET_PING_REPLY [/COLOR][COLOR=#098658]22[/COLOR]
[COLOR=#af00db]#define[/COLOR][COLOR=#0000ff] GET_CAL_FACTORS [/COLOR][COLOR=#098658]25[/COLOR]
[COLOR=#af00db]#define[/COLOR][COLOR=#0000ff] GET_HASH [/COLOR][COLOR=#098658]29[/COLOR]
[COLOR=#008000]//#define GET_SPI_1               30[/COLOR]
[COLOR=#008000]//#define GET_SPI_2               31[/COLOR]
[COLOR=#af00db]#define[/COLOR][COLOR=#0000ff] GET_I_VALUE [/COLOR][COLOR=#098658]32[/COLOR]

[COLOR=#af00db]#define[/COLOR][COLOR=#0000ff] PING_SECRET [/COLOR][COLOR=#098658]1234[/COLOR]
[COLOR=#008000]//[/COLOR]
[COLOR=#af00db]#define[/COLOR][COLOR=#0000ff] GET_PROCESSOR_NAME [/COLOR][COLOR=#098658]40[/COLOR][COLOR=#008000]    // The 'GET' prefix indicates a command that expects a reply (the host will wait up to 250mS)[/COLOR]
[COLOR=#af00db]#define[/COLOR][COLOR=#0000ff] GET_PROGRAM_VERSION [/COLOR][COLOR=#098658]41[/COLOR]
[COLOR=#af00db]#define[/COLOR][COLOR=#0000ff] GET_MACHINE_NAME [/COLOR][COLOR=#098658]42[/COLOR]
[COLOR=#af00db]#define[/COLOR][COLOR=#0000ff] GET_MACHINE_POSITION_XYZ [/COLOR][COLOR=#098658]43[/COLOR]
[COLOR=#af00db]#define[/COLOR][COLOR=#0000ff] GET_MACHINE_POSITION_UVW [/COLOR][COLOR=#098658]44[/COLOR]
[COLOR=#af00db]#define[/COLOR][COLOR=#0000ff] GET_MACHINE_POSITION_ABC [/COLOR][COLOR=#098658]45[/COLOR]
[COLOR=#af00db]#define[/COLOR][COLOR=#0000ff] GET_MACHINE_STATE [/COLOR][COLOR=#098658]46[/COLOR]
[COLOR=#af00db]#define[/COLOR][COLOR=#0000ff] GET_MACHINE_ERRORS [/COLOR][COLOR=#098658]47[/COLOR]
[COLOR=#af00db]#define[/COLOR][COLOR=#0000ff] GET_GCODE_ERRORS [/COLOR][COLOR=#098658]48[/COLOR]
[COLOR=#af00db]#define[/COLOR][COLOR=#0000ff] GET_MESSAGE_ERRORS [/COLOR][COLOR=#098658]49[/COLOR]
[COLOR=#af00db]#define[/COLOR][COLOR=#0000ff] GET_UART_BUFFER_COUNT [/COLOR][COLOR=#098658]50[/COLOR]
[COLOR=#af00db]#define[/COLOR][COLOR=#0000ff] GET_EVENT_QUEUE_COUNT [/COLOR][COLOR=#098658]51[/COLOR]
[COLOR=#af00db]#define[/COLOR][COLOR=#0000ff] GET_UART_LINE_COUNT [/COLOR][COLOR=#098658]52[/COLOR]
[COLOR=#af00db]#define[/COLOR][COLOR=#0000ff] GET_EVENT_QUEUE_ITEM [/COLOR][COLOR=#098658]53[/COLOR]
[COLOR=#af00db]#define[/COLOR][COLOR=#0000ff] GET_EVENT_QUEUE_STATUS [/COLOR][COLOR=#098658]54[/COLOR]
[COLOR=#af00db]#define[/COLOR][COLOR=#0000ff] GET_XML_ERRORS [/COLOR][COLOR=#098658]55[/COLOR]
[COLOR=#af00db]#define[/COLOR][COLOR=#0000ff] GET_CONSOLE_ERRORS [/COLOR][COLOR=#098658]56[/COLOR]
[COLOR=#af00db]#define[/COLOR][COLOR=#0000ff] GET_EVENT_QUEUE_NEXT_ITEM [/COLOR][COLOR=#098658]57[/COLOR]
[COLOR=#af00db]#define[/COLOR][COLOR=#0000ff] GET_EXEC_CLEAR_EVENTS [/COLOR][COLOR=#098658]58[/COLOR]
[COLOR=#af00db]#define[/COLOR][COLOR=#0000ff] GET_EVENT_QUEUE_NEXT [/COLOR][COLOR=#098658]59[/COLOR]
[COLOR=#af00db]#define[/COLOR][COLOR=#0000ff] GET_SET_TIMER3_RATE [/COLOR][COLOR=#098658]70[/COLOR]

[COLOR=#af00db]#define[/COLOR][COLOR=#0000ff] PUT_RESET_XYZ [/COLOR][COLOR=#098658]60[/COLOR]
[COLOR=#af00db]#define[/COLOR][COLOR=#0000ff] PUT_RESET_ABC [/COLOR][COLOR=#098658]61[/COLOR]
[COLOR=#af00db]#define[/COLOR][COLOR=#0000ff] PUT_RESET_UVW [/COLOR][COLOR=#098658]62[/COLOR]
[COLOR=#008000]//[/COLOR]
[COLOR=#af00db]#define[/COLOR][COLOR=#0000ff] GET_EXEC_GCODE [/COLOR][COLOR=#098658]6000[/COLOR]
[COLOR=#008000]//[/COLOR]
[COLOR=#af00db]#define[/COLOR][COLOR=#0000ff] PUT_MODE_CLEAR [/COLOR][COLOR=#098658]5000[/COLOR][COLOR=#008000]   // The 'PUT' prefix indicates a command that doesn't expect a reply (the host won't wait becuse it doesn't expect a reply)[/COLOR]
[COLOR=#af00db]#define[/COLOR][COLOR=#0000ff] PUT_MODE_VERBOSE [/COLOR][COLOR=#098658]5001[/COLOR]
[COLOR=#af00db]#define[/COLOR][COLOR=#0000ff] PUT_MODE_PAUSED [/COLOR][COLOR=#098658]5002[/COLOR]
[COLOR=#af00db]#define[/COLOR][COLOR=#0000ff] PUT_MODE_DEBUG [/COLOR][COLOR=#098658]5003[/COLOR]
[COLOR=#af00db]#define[/COLOR][COLOR=#0000ff] PUT_MODE_SINGLE_STEP [/COLOR][COLOR=#098658]5004[/COLOR]
[COLOR=#af00db]#define[/COLOR][COLOR=#0000ff] PUT_MODE_LOG [/COLOR][COLOR=#098658]5005[/COLOR]
[COLOR=#af00db]#define[/COLOR][COLOR=#0000ff] PUT_MODE_RUN [/COLOR][COLOR=#098658]5006[/COLOR]
[COLOR=#af00db]#define[/COLOR][COLOR=#0000ff] PUT_MODE_STOP [/COLOR][COLOR=#098658]5007[/COLOR]
[COLOR=#af00db]#define[/COLOR][COLOR=#0000ff] PUT_MODE_SYSTEM_HALT [/COLOR][COLOR=#098658]5008[/COLOR]
[COLOR=#af00db]#define[/COLOR][COLOR=#0000ff] PUT_MODE_GLOBAL_OVERRIDE [/COLOR][COLOR=#098658]5009[/COLOR]
[COLOR=#af00db]#define[/COLOR][COLOR=#0000ff] PUT_MODE_TEST [/COLOR][COLOR=#098658]5010[/COLOR]
[COLOR=#af00db]#define[/COLOR][COLOR=#0000ff] PUT_CLEAR_GCODE_ERRORS [/COLOR][COLOR=#098658]5011[/COLOR]
[COLOR=#af00db]#define[/COLOR][COLOR=#0000ff] PUT_CLEAR_MACHINE_ERRORS [/COLOR][COLOR=#098658]5012[/COLOR]
[COLOR=#af00db]#define[/COLOR][COLOR=#0000ff] PUT_CLEAR_MESSAGE_ERRORS [/COLOR][COLOR=#098658]5013[/COLOR]
[COLOR=#af00db]#define[/COLOR][COLOR=#0000ff] PUT_TEST_FUNCTION [/COLOR][COLOR=#098658]5014[/COLOR]
[COLOR=#af00db]#define[/COLOR][COLOR=#0000ff] PUT_SET_TARE [/COLOR][COLOR=#098658]5015[/COLOR]
[COLOR=#af00db]#define[/COLOR][COLOR=#0000ff] PUT_RESET_TARE [/COLOR][COLOR=#098658]5016[/COLOR]
[COLOR=#af00db]#define[/COLOR][COLOR=#0000ff] PUT_MACHINE_FUNCTION [/COLOR][COLOR=#098658]5017[/COLOR]
[COLOR=#af00db]#define[/COLOR][COLOR=#0000ff] PUT_SYSTEM_RESET [/COLOR][COLOR=#098658]5018[/COLOR]
[COLOR=#af00db]#define[/COLOR][COLOR=#0000ff] PUT_EVENT_QUEUE_ITEM [/COLOR][COLOR=#098658]5019[/COLOR]
[COLOR=#af00db]#define[/COLOR][COLOR=#0000ff] PUT_EVENT_QUEUE_GCODE [/COLOR][COLOR=#098658]5020[/COLOR]

[COLOR=#008000]//------------------------------------------------------------------------------[/COLOR]
[COLOR=#008000]// axis constants[/COLOR]
[COLOR=#008000]//------------------------------------------------------------------------------[/COLOR]
[COLOR=#af00db]#define[/COLOR][COLOR=#0000ff] N_AXES [/COLOR][COLOR=#098658]9[/COLOR]
[COLOR=#af00db]#define[/COLOR][COLOR=#0000ff] N_ORIGINS [/COLOR][COLOR=#098658]32[/COLOR]
[COLOR=#af00db]#define[/COLOR][COLOR=#0000ff] N_TOOLS [/COLOR][COLOR=#098658]24[/COLOR]
[COLOR=#af00db]#define[/COLOR][COLOR=#0000ff] NAME_WIDTH [/COLOR][COLOR=#098658]16[/COLOR]
[COLOR=#008000]//------------------------------------------------------------------------------[/COLOR]
[COLOR=#008000]// step ratios for microstepping[/COLOR]
[COLOR=#008000]//------------------------------------------------------------------------------[/COLOR]
[COLOR=#af00db]#define[/COLOR][COLOR=#0000ff] STEP_BASE [/COLOR][COLOR=#098658]200[/COLOR][COLOR=#008000]   // native stepper resolution = 200 steps per rev (1.8 degrees per step)[/COLOR]
[COLOR=#af00db]#define[/COLOR][COLOR=#0000ff] STEP_400 [/COLOR][COLOR=#098658]400[/COLOR][COLOR=#008000]    // 400 steps per rev[/COLOR]
[COLOR=#af00db]#define[/COLOR][COLOR=#0000ff] STEP_800 [/COLOR][COLOR=#098658]800[/COLOR][COLOR=#008000]    // ...[/COLOR]
[COLOR=#af00db]#define[/COLOR][COLOR=#0000ff] STEP_1000 [/COLOR][COLOR=#098658]1000[/COLOR][COLOR=#008000]  // this probably plenty. (0.36 degrees per step)[/COLOR]
[COLOR=#af00db]#define[/COLOR][COLOR=#0000ff] STEP_1600 [/COLOR][COLOR=#098658]1600[/COLOR][COLOR=#008000]  // ...[/COLOR]
[COLOR=#af00db]#define[/COLOR][COLOR=#0000ff] STEP_2000 [/COLOR][COLOR=#098658]2000[/COLOR]
[COLOR=#af00db]#define[/COLOR][COLOR=#0000ff] STEP_3200 [/COLOR][COLOR=#098658]3200[/COLOR]
[COLOR=#af00db]#define[/COLOR][COLOR=#0000ff] STEP_4000 [/COLOR][COLOR=#098658]4000[/COLOR]
[COLOR=#af00db]#define[/COLOR][COLOR=#0000ff] STEP_5000 [/COLOR][COLOR=#098658]5000[/COLOR]
[COLOR=#af00db]#define[/COLOR][COLOR=#0000ff] STEP_6400 [/COLOR][COLOR=#098658]6400[/COLOR]
[COLOR=#af00db]#define[/COLOR][COLOR=#0000ff] STEP_8000 [/COLOR][COLOR=#098658]8000[/COLOR]
[COLOR=#af00db]#define[/COLOR][COLOR=#0000ff] STEP_10000 [/COLOR][COLOR=#098658]10000[/COLOR]
[COLOR=#af00db]#define[/COLOR][COLOR=#0000ff] STEP_12800 [/COLOR][COLOR=#098658]12800[/COLOR]
[COLOR=#af00db]#define[/COLOR][COLOR=#0000ff] STEP_20000 [/COLOR][COLOR=#098658]20000[/COLOR]
[COLOR=#af00db]#define[/COLOR][COLOR=#0000ff] STEP_25000 [/COLOR][COLOR=#098658]25000[/COLOR]
[COLOR=#008000]//------------------------------------------------------------------------------[/COLOR]
[COLOR=#008000]// lathe axis constants[/COLOR]
[COLOR=#008000]//------------------------------------------------------------------------------[/COLOR]
[COLOR=#af00db]#define[/COLOR][COLOR=#0000ff] DEFAULT_AXIS_CLASS ac_null[/COLOR]
[COLOR=#af00db]#define[/COLOR][COLOR=#0000ff] DEFAULT_MACHINE_UNITS mu_millimeters[/COLOR]
[COLOR=#af00db]#define[/COLOR][COLOR=#0000ff] DEFAULT_STEPS_REV STEP_400[/COLOR]
[COLOR=#af00db]#define[/COLOR][COLOR=#0000ff] DEFAULT_LEAD_SCREW_PITCH [/COLOR][COLOR=#098658]3.0[/COLOR]
[COLOR=#af00db]#define[/COLOR][COLOR=#0000ff] DEFAULT_GEAR_RATIO [/COLOR][COLOR=#098658]7.2[/COLOR]
[COLOR=#008000]//----------------------------------------------------------------------------[/COLOR]
[COLOR=#008000]// structs and typedefs[/COLOR]
[COLOR=#008000]//----------------------------------------------------------------------------[/COLOR]
[COLOR=#0000ff]typedef[/COLOR] [COLOR=#0000ff]union[/COLOR] {
  [COLOR=#0000ff]int[/COLOR] bits;
  [COLOR=#0000ff]struct[/COLOR]
  {
    [COLOR=#0000ff]unsigned[/COLOR] float_error : [COLOR=#098658]1[/COLOR];
    [COLOR=#0000ff]unsigned[/COLOR] integer_error : [COLOR=#098658]1[/COLOR];
    [COLOR=#0000ff]unsigned[/COLOR] parameter_error : [COLOR=#098658]1[/COLOR];
    [COLOR=#0000ff]unsigned[/COLOR] unknown_xml_tag : [COLOR=#098658]1[/COLOR];
    [COLOR=#0000ff]unsigned[/COLOR] unknown_value : [COLOR=#098658]1[/COLOR];
    [COLOR=#0000ff]unsigned[/COLOR] parse_error : [COLOR=#098658]1[/COLOR];
    [COLOR=#0000ff]unsigned[/COLOR] invalid_char : [COLOR=#098658]1[/COLOR];
    [COLOR=#0000ff]unsigned[/COLOR] value_error : [COLOR=#098658]1[/COLOR];
    [COLOR=#0000ff]unsigned[/COLOR] missing_xml_tag : [COLOR=#098658]1[/COLOR];
    [COLOR=#0000ff]unsigned[/COLOR] missing_field : [COLOR=#098658]1[/COLOR];
    [COLOR=#0000ff]unsigned[/COLOR] unexpected_field : [COLOR=#098658]1[/COLOR];
    [COLOR=#0000ff]unsigned[/COLOR] unknown_xml_cmd : [COLOR=#098658]1[/COLOR];
    [COLOR=#0000ff]unsigned[/COLOR] missing_xml_msg : [COLOR=#098658]1[/COLOR];
    [COLOR=#0000ff]unsigned[/COLOR] missing_xml_cmd : [COLOR=#098658]1[/COLOR];
    [COLOR=#0000ff]unsigned[/COLOR] missing_xml_data : [COLOR=#098658]1[/COLOR];
    [COLOR=#0000ff]unsigned[/COLOR] missing_xml_hash : [COLOR=#098658]1[/COLOR];
    [COLOR=#0000ff]unsigned[/COLOR] hash_mismatch : [COLOR=#098658]1[/COLOR];
  };
} [COLOR=#267f99]T_xml_errors[/COLOR];[COLOR=#008000]  // xml parser/format errors[/COLOR]

[COLOR=#0000ff]typedef[/COLOR] [COLOR=#0000ff]union[/COLOR] {
  [COLOR=#0000ff]int[/COLOR] bits;
  [COLOR=#0000ff]struct[/COLOR]
  {
    [COLOR=#0000ff]unsigned[/COLOR] overrun : [COLOR=#098658]1[/COLOR];
    [COLOR=#0000ff]unsigned[/COLOR] parity : [COLOR=#098658]1[/COLOR];
    [COLOR=#0000ff]unsigned[/COLOR] idle : [COLOR=#098658]1[/COLOR];
    [COLOR=#0000ff]unsigned[/COLOR] noise : [COLOR=#098658]1[/COLOR];
    [COLOR=#0000ff]unsigned[/COLOR] line_too_long : [COLOR=#098658]1[/COLOR];
  };
} [COLOR=#267f99]T_console_errors[/COLOR];[COLOR=#008000]  // console (UART) errors[/COLOR]

[COLOR=#0000ff]typedef[/COLOR] [COLOR=#0000ff]union[/COLOR] {
  [COLOR=#0000ff]int[/COLOR] bits;
  [COLOR=#0000ff]struct[/COLOR]
  {
    [COLOR=#0000ff]unsigned[/COLOR] missing_block : [COLOR=#098658]1[/COLOR];
    [COLOR=#0000ff]unsigned[/COLOR] block_too_long : [COLOR=#098658]1[/COLOR];
    [COLOR=#0000ff]unsigned[/COLOR] unknown_gc_token : [COLOR=#098658]1[/COLOR];
    [COLOR=#0000ff]unsigned[/COLOR] bad_float_format : [COLOR=#098658]1[/COLOR];
    [COLOR=#0000ff]unsigned[/COLOR] bad_integer_format : [COLOR=#098658]1[/COLOR];
    [COLOR=#0000ff]unsigned[/COLOR] too_many_arguments : [COLOR=#098658]1[/COLOR];
    [COLOR=#0000ff]unsigned[/COLOR] missing_comment_brace : [COLOR=#098658]1[/COLOR];
  };
} [COLOR=#267f99]T_gc_parse_errors[/COLOR];
[COLOR=#008000]//------------------------------------------------------------------------------[/COLOR]
[COLOR=#008000]// parser context for gcode.[/COLOR]
[COLOR=#008000]//------------------------------------------------------------------------------[/COLOR]
[COLOR=#0000ff]typedef[/COLOR] [COLOR=#0000ff]struct[/COLOR]
{
  T_gc_parse_errors gc_errors;[COLOR=#008000]          // error flags[/COLOR]
  [COLOR=#0000ff]char[/COLOR] [COLOR=#001080]last_error_desc[/COLOR][[COLOR=#098658]64[/COLOR]];[COLOR=#008000]             // last error[/COLOR]
  [COLOR=#0000ff]char[/COLOR] [COLOR=#001080]comments[/COLOR][COMMENT_LENGTH];[COLOR=#008000]        // last comment[/COLOR]
  [COLOR=#0000ff]int[/COLOR] argc;[COLOR=#008000]                             // number of gcode tokens in gcode block.[/COLOR]
  [COLOR=#0000ff]int[/COLOR] g;[COLOR=#008000]                                // count of G fields[/COLOR]
  [COLOR=#0000ff]int[/COLOR] m;[COLOR=#008000]                                // count of M fields[/COLOR]
  [COLOR=#0000ff]char[/COLOR] *[COLOR=#001080]args[/COLOR][MAX_ARGS];[COLOR=#008000]                 // list of pointers to gcodes and values in gc_codeparams[].[/COLOR]
  [COLOR=#0000ff]char[/COLOR] [COLOR=#001080]gc_codeblock[/COLOR][COMMAND_LENGTH];[COLOR=#008000]    // incomimg gcode command line.[/COLOR]
  [COLOR=#0000ff]char[/COLOR] [COLOR=#001080]gc_codestrings[/COLOR][COMMAND_LENGTH];[COLOR=#008000]  // cleaned up and parsed gcode fields[/COLOR]
  [COLOR=#0000ff]char[/COLOR] [COLOR=#001080]gc_codeparams[/COLOR][COMMAND_LENGTH];[COLOR=#008000]   // full list of all commands and parameters in a block[/COLOR]
} [COLOR=#267f99]T_gcparser[/COLOR];
[COLOR=#008000]// enumerated list of event class(es).[/COLOR]
[COLOR=#0000ff]typedef[/COLOR] [COLOR=#0000ff]enum[/COLOR] { [COLOR=#0070c1]ec_null[/COLOR],
               [COLOR=#0070c1]ec_move_axis[/COLOR],
               [COLOR=#0070c1]ec_select_tool[/COLOR],
               [COLOR=#0070c1]ec_adjust_parameter[/COLOR] } T_event_class;
[COLOR=#008000]// enumerated list of machine event(s)[/COLOR]
[COLOR=#0000ff]typedef[/COLOR] [COLOR=#0000ff]enum[/COLOR] { [COLOR=#0070c1]me_null[/COLOR],
               [COLOR=#0070c1]me_move[/COLOR],
               [COLOR=#0070c1]me_traverse[/COLOR],
               [COLOR=#0070c1]me_select_tool[/COLOR],
               [COLOR=#0070c1]me_test[/COLOR],
               [COLOR=#0070c1]me_set_pid[/COLOR],
               [COLOR=#0070c1]me_get_data[/COLOR],
               [COLOR=#0070c1]me_exec_gcode[/COLOR] } T_machine_events;
[COLOR=#008000]// enumerated list of possible machine function mode(s)[/COLOR]
[COLOR=#0000ff]typedef[/COLOR] [COLOR=#0000ff]enum[/COLOR] { [COLOR=#0070c1]fm_null[/COLOR],
               [COLOR=#0070c1]fm_paused[/COLOR],
               [COLOR=#0070c1]fm_single_step[/COLOR],
               [COLOR=#0070c1]fm_jog[/COLOR],
               [COLOR=#0070c1]fm_manual[/COLOR],
               [COLOR=#0070c1]fm_wait_for_tool[/COLOR] } T_function_mode;
[COLOR=#008000]//[/COLOR]
[COLOR=#0000ff]typedef[/COLOR] [COLOR=#0000ff]union[/COLOR] {
  [COLOR=#0000ff]int[/COLOR] bits;
  [COLOR=#0000ff]struct[/COLOR]
  {
    [COLOR=#0000ff]unsigned[/COLOR] a_changed : [COLOR=#098658]1[/COLOR];
    [COLOR=#0000ff]unsigned[/COLOR] b_changed : [COLOR=#098658]1[/COLOR];
    [COLOR=#0000ff]unsigned[/COLOR] c_changed : [COLOR=#098658]1[/COLOR];
    [COLOR=#0000ff]unsigned[/COLOR] d_changed : [COLOR=#098658]1[/COLOR];
    [COLOR=#0000ff]unsigned[/COLOR] e_changed : [COLOR=#098658]1[/COLOR];
    [COLOR=#0000ff]unsigned[/COLOR] f_changed : [COLOR=#098658]1[/COLOR];
    [COLOR=#0000ff]unsigned[/COLOR] g_changed : [COLOR=#098658]1[/COLOR];
    [COLOR=#0000ff]unsigned[/COLOR] h_changed : [COLOR=#098658]1[/COLOR];
    [COLOR=#0000ff]unsigned[/COLOR] i_changed : [COLOR=#098658]1[/COLOR];
    [COLOR=#0000ff]unsigned[/COLOR] j_changed : [COLOR=#098658]1[/COLOR];
    [COLOR=#0000ff]unsigned[/COLOR] k_changed : [COLOR=#098658]1[/COLOR];
    [COLOR=#0000ff]unsigned[/COLOR] l_changed : [COLOR=#098658]1[/COLOR];
    [COLOR=#0000ff]unsigned[/COLOR] m_changed : [COLOR=#098658]1[/COLOR];
    [COLOR=#0000ff]unsigned[/COLOR] n_changed : [COLOR=#098658]1[/COLOR];
    [COLOR=#0000ff]unsigned[/COLOR] o_changed : [COLOR=#098658]1[/COLOR];
    [COLOR=#0000ff]unsigned[/COLOR] p_changed : [COLOR=#098658]1[/COLOR];
    [COLOR=#0000ff]unsigned[/COLOR] q_changed : [COLOR=#098658]1[/COLOR];
    [COLOR=#0000ff]unsigned[/COLOR] r_changed : [COLOR=#098658]1[/COLOR];
    [COLOR=#0000ff]unsigned[/COLOR] s_changed : [COLOR=#098658]1[/COLOR];
    [COLOR=#0000ff]unsigned[/COLOR] t_changed : [COLOR=#098658]1[/COLOR];
    [COLOR=#0000ff]unsigned[/COLOR] u_changed : [COLOR=#098658]1[/COLOR];
    [COLOR=#0000ff]unsigned[/COLOR] v_changed : [COLOR=#098658]1[/COLOR];
    [COLOR=#0000ff]unsigned[/COLOR] w_changed : [COLOR=#098658]1[/COLOR];
    [COLOR=#0000ff]unsigned[/COLOR] x_changed : [COLOR=#098658]1[/COLOR];
    [COLOR=#0000ff]unsigned[/COLOR] y_changed : [COLOR=#098658]1[/COLOR];
    [COLOR=#0000ff]unsigned[/COLOR] z_changed : [COLOR=#098658]1[/COLOR];
  };
} [COLOR=#267f99]T_field_flags[/COLOR];
[COLOR=#008000]//------------------------------------------------------------------------------[/COLOR]
[COLOR=#008000]// An 'event' is something synchronous that may be initiated by the system.[/COLOR]
[COLOR=#008000]// Typically, 'something' we want the controller to do in an ordered sequential way.[/COLOR]
[COLOR=#008000]// example: move an axis, attach a tool, adjust a parameter etc.[/COLOR]
[COLOR=#008000]//------------------------------------------------------------------------------[/COLOR]
[COLOR=#0000ff]typedef[/COLOR] [COLOR=#0000ff]struct[/COLOR]
{
  [COLOR=#0000ff]int[/COLOR] line_number;[COLOR=#008000]                //[/COLOR]
  [COLOR=#0000ff]int[/COLOR] [COLOR=#001080]gcode_param[/COLOR][GC_PER_BLOCK];[COLOR=#008000]  // active gcodes per block[/COLOR]
  [COLOR=#0000ff]int[/COLOR] [COLOR=#001080]mcode_param[/COLOR][MC_PER_BLOCK];[COLOR=#008000]  // active mcodes per block[/COLOR]
  [COLOR=#0000ff]int[/COLOR] tool_select;[COLOR=#008000]                // new tool[/COLOR]
  [COLOR=#0000ff]float[/COLOR] feed_rate;[COLOR=#008000]                //[/COLOR]
  [COLOR=#0000ff]float[/COLOR] speed;[COLOR=#008000]                    //[/COLOR]
  [COLOR=#0000ff]int[/COLOR] dwell_time;[COLOR=#008000]                 //[/COLOR]
  [COLOR=#0000ff]float[/COLOR] radius;[COLOR=#008000]                   //[/COLOR]
  [COLOR=#0000ff]int[/COLOR] coord_index;[COLOR=#008000]                // relative coordinates index[/COLOR]
  [COLOR=#0000ff]int[/COLOR] op_mode;[COLOR=#008000]                    // new mode[/COLOR]
  [COLOR=#0000ff]float[/COLOR] [COLOR=#001080]xyz[/COLOR][MAX_EVENT_PARAMS];[COLOR=#008000]    // 'x,y,z' stored here.[/COLOR]
  [COLOR=#0000ff]float[/COLOR] [COLOR=#001080]abc[/COLOR][MAX_EVENT_PARAMS];[COLOR=#008000]    // 'a,b,c' stored here.[/COLOR]
  [COLOR=#0000ff]float[/COLOR] [COLOR=#001080]uvw[/COLOR][MAX_EVENT_PARAMS];[COLOR=#008000]    // 'u,v,w' stored here.[/COLOR]
  T_field_flags field_flags;
} [COLOR=#267f99]T_event[/COLOR];
[COLOR=#008000]//------------------------------------------------------------------------------[/COLOR]
[COLOR=#008000]// booleans for setting the state of an 'event_queue'[/COLOR]
[COLOR=#008000]//------------------------------------------------------------------------------[/COLOR]
[COLOR=#0000ff]typedef[/COLOR] [COLOR=#0000ff]union[/COLOR] {
  [COLOR=#0000ff]int[/COLOR] bits;
  [COLOR=#0000ff]struct[/COLOR]
  {
    [COLOR=#0000ff]unsigned[/COLOR] busy : [COLOR=#098658]1[/COLOR];[COLOR=#008000]     // 'busy' means an event is underway and we have to wait until the event is ended.[/COLOR]
    [COLOR=#0000ff]unsigned[/COLOR] paused : [COLOR=#098658]1[/COLOR];[COLOR=#008000]   // 'paused' means we are temporarily halting the whole process.[/COLOR]
    [COLOR=#0000ff]unsigned[/COLOR] fault : [COLOR=#098658]1[/COLOR];[COLOR=#008000]    // 'fault' means the system has struck a significnt event that needs operator intervention.[/COLOR]
    [COLOR=#0000ff]unsigned[/COLOR] waiting : [COLOR=#098658]1[/COLOR];[COLOR=#008000]  // 'waiting' for user input.(active prompt)[/COLOR]
    [COLOR=#0000ff]unsigned[/COLOR] ready : [COLOR=#098658]1[/COLOR];[COLOR=#008000]    // 'ready' indicates all dependant fuctions have finished and ready for the next event (eg x,y,z axes - this is an AND function)[/COLOR]
    [COLOR=#0000ff]unsigned[/COLOR] full : [COLOR=#098658]1[/COLOR];[COLOR=#008000]     // 'full' indicates that the queue_buffer is full - don't post any new event sequences.[/COLOR]
  };
} [COLOR=#267f99]T_queue_state[/COLOR];
[COLOR=#008000]//------------------------------------------------------------------------------[/COLOR]
[COLOR=#008000]// scale and offsets used for each move.[/COLOR]
[COLOR=#008000]//------------------------------------------------------------------------------[/COLOR]
[COLOR=#0000ff]typedef[/COLOR] [COLOR=#0000ff]struct[/COLOR]
{
  [COLOR=#0000ff]float[/COLOR] scale;[COLOR=#008000]  // y = mx + c  -  integer step calculation, plus offset[/COLOR]
  [COLOR=#0000ff]float[/COLOR] offset;
} [COLOR=#267f99]T_scalar_coeffs[/COLOR];[COLOR=#008000]  // these are used to calculate the number of steps required to move a calibrated distance (mm or inches)[/COLOR]
[COLOR=#008000]//------------------------------------------------------------------------------[/COLOR]
[COLOR=#008000]// 'T_event_queue' maintains a list of the events in an array buffer, say, 32 events long. (must be a power of 2)[/COLOR]
[COLOR=#008000]// 'head' points to the last event pushed (buffered & ready for processing, - it's the last event to be extracted from the queue).[/COLOR]
[COLOR=#008000]// 'tail' points to the first event pushed (and will be the first event in order, extracted from the queue).[/COLOR]
[COLOR=#008000]// 'count' calculates the number of events left in the queue.[/COLOR]
[COLOR=#008000]// 'busy' determines if an event is being run currently.[/COLOR]
[COLOR=#008000]// 'full' stops new events being posted to the queue.[/COLOR]
[COLOR=#008000]// How it works:[/COLOR]
[COLOR=#008000]// This structure uses a virtual method table concept plus an array[] of events, set into global memory.[/COLOR]
[COLOR=#008000]// This format enables functions (methods) with a dot '.' operator syntax.[/COLOR]
[COLOR=#008000]// Examples:[/COLOR]
[COLOR=#008000]// 1) event_queue.add(an_event);         // copies an event structure into an array of event structures.[/COLOR]
[COLOR=#008000]// 2) an_event = event_queue.next();     // retrieves a pointer to an event from the next one in the buffered array.[/COLOR]
[COLOR=#008000]// 3) event_count = event_queue.count(); // retrieves the current number of events in the queue.[/COLOR]
[COLOR=#008000]//------------------------------------------------------------------------------[/COLOR]
[COLOR=#0000ff]typedef[/COLOR] [COLOR=#0000ff]struct[/COLOR]
{
  T_event [COLOR=#001080]events[/COLOR][MAX_EVENT_QUEUE];[COLOR=#008000]            // circular buffer of events in an array. (must be a power of 2)[/COLOR]
  T_function_mode function_mode;[COLOR=#008000]              // e.g. fm_paused, fm_single_step, fm_jog etc[/COLOR]
  T_queue_state state;[COLOR=#008000]                        // 'busy', 'paused', 'halted', 'full' etc.[/COLOR]
  T_scalar_coeffs [COLOR=#001080]scalar_coeffs[/COLOR][MAX_COEFFS];[COLOR=#008000]  // array of coordinates used.[/COLOR]
  [COLOR=#0000ff]int[/COLOR] total;[COLOR=#008000]                                  //[/COLOR]
  [COLOR=#0000ff]int[/COLOR] head;[COLOR=#008000]                                   // 'head is incremented and the next event is posted to the head of the buffer.[/COLOR]
  [COLOR=#0000ff]int[/COLOR] tail;[COLOR=#008000]                                   // 'tail' is where the next event is taken from in the circular buffer.[/COLOR]
  [COLOR=#267f99]T_event[/COLOR] [COLOR=#0000ff]*[/COLOR](*[COLOR=#001080]next[/COLOR])([COLOR=#0000ff]void[/COLOR]);[COLOR=#008000]                     // 'next' gets the next event from the list if one is available. returns 'null' otherwise.[/COLOR]
  [COLOR=#0000ff]void[/COLOR] (*[COLOR=#001080]add[/COLOR])([COLOR=#267f99]T_event[/COLOR] [COLOR=#0000ff]*[/COLOR][COLOR=#001080]e[/COLOR]);[COLOR=#008000]                    // 'add' appends a new event to the buffer unless buffer is (near)ly full.[/COLOR]
  [COLOR=#0000ff]int[/COLOR] (*[COLOR=#001080]count[/COLOR])([COLOR=#0000ff]void[/COLOR]);[COLOR=#008000]                         // 'count' calculates and returns the number of events in the (circular) buffer.[/COLOR]
} [COLOR=#267f99]T_event_queue[/COLOR];
[COLOR=#008000]//------------------------------------------------------------------------------[/COLOR]
[COLOR=#008000]// enumerated type of the kinds of axes we can have and how they are measured.[/COLOR]
[COLOR=#008000]// ac_null   no effect[/COLOR]
[COLOR=#008000]// ac dist   calibrated in distance values; mm or inch[/COLOR]
[COLOR=#008000]// ac_speed  calibrated in speed  - RPM[/COLOR]
[COLOR=#008000]// ac_angle  calibrated in angles. (degrees or radians)[/COLOR]
[COLOR=#008000]//------------------------------------------------------------------------------[/COLOR]
[COLOR=#0000ff]typedef[/COLOR] [COLOR=#0000ff]enum[/COLOR] { [COLOR=#0070c1]ac_null[/COLOR],
               [COLOR=#0070c1]ac_dist[/COLOR],
               [COLOR=#0070c1]ac_speed[/COLOR],
               [COLOR=#0070c1]ac_angle[/COLOR] } T_axis_class;
[COLOR=#008000]//------------------------------------------------------------------------------[/COLOR]
[COLOR=#0000ff]typedef[/COLOR] [COLOR=#0000ff]enum[/COLOR] { [COLOR=#0070c1]mu_null[/COLOR],
               [COLOR=#0070c1]mu_millimeters[/COLOR],
               [COLOR=#0070c1]mu_inches[/COLOR] } T_machine_units;
[COLOR=#008000]//------------------------------------------------------------------------------[/COLOR]
[COLOR=#0000ff]typedef[/COLOR] [COLOR=#0000ff]enum[/COLOR] { [COLOR=#0070c1]mc_null[/COLOR],
               [COLOR=#0070c1]mc_program_stop[/COLOR],
               [COLOR=#0070c1]mc_optional_stop[/COLOR],
               [COLOR=#0070c1]mc_spindle_on[/COLOR],
               [COLOR=#0070c1]mc_spindle_off[/COLOR],
               [COLOR=#0070c1]mc_tool_change[/COLOR],
               [COLOR=#0070c1]mc_end_program[/COLOR] } T_machine_m_codes;
[COLOR=#008000]//------------------------------------------------------------------------------[/COLOR]
[COLOR=#0000ff]typedef[/COLOR] [COLOR=#0000ff]struct[/COLOR]
{
  [COLOR=#0000ff]char[/COLOR] [COLOR=#001080]name[/COLOR][NAME_WIDTH];
  [COLOR=#0000ff]float[/COLOR] [COLOR=#001080]pt[/COLOR][[COLOR=#098658]3[/COLOR]];[COLOR=#008000]  // three floats that can be aliased as xyz, abc, uvw.[/COLOR]
} [COLOR=#267f99]T_origin_pt[/COLOR];
[COLOR=#008000]//------------------------------------------------------------------------------[/COLOR]
[COLOR=#0000ff]typedef[/COLOR] [COLOR=#0000ff]union[/COLOR] {
  [COLOR=#0000ff]int[/COLOR] bits;
  [COLOR=#0000ff]struct[/COLOR]
  {
    [COLOR=#0000ff]unsigned[/COLOR] use_ramp : [COLOR=#098658]1[/COLOR];[COLOR=#008000]       //[/COLOR]
    [COLOR=#0000ff]unsigned[/COLOR] modal : [COLOR=#098658]1[/COLOR];[COLOR=#008000]          //[/COLOR]
    [COLOR=#0000ff]unsigned[/COLOR] abs_mode : [COLOR=#098658]1[/COLOR];[COLOR=#008000]       //[/COLOR]
    [COLOR=#0000ff]unsigned[/COLOR] use_tool_comp : [COLOR=#098658]1[/COLOR];[COLOR=#008000]  //[/COLOR]
    [COLOR=#0000ff]unsigned[/COLOR] units_type : [COLOR=#098658]2[/COLOR];[COLOR=#008000]     //[/COLOR]
    [COLOR=#0000ff]unsigned[/COLOR] changed : [COLOR=#098658]1[/COLOR];[COLOR=#008000]        // whether the machine has changed any parameter.[/COLOR]
    [COLOR=#0000ff]unsigned[/COLOR] enabled : [COLOR=#098658]1[/COLOR];[COLOR=#008000]        // global enabled for the machine to run.[/COLOR]
  };
} [COLOR=#267f99]T_machine_state[/COLOR];
[COLOR=#008000]//------------------------------------------------------------------------------[/COLOR]
[COLOR=#0000ff]typedef[/COLOR] [COLOR=#0000ff]struct[/COLOR]
{
  [COLOR=#0000ff]float[/COLOR] [COLOR=#001080]ramp_steps[/COLOR][[COLOR=#098658]3[/COLOR]];
  [COLOR=#0000ff]float[/COLOR] [COLOR=#001080]ramp_gradient[/COLOR][[COLOR=#098658]3[/COLOR]];
  [COLOR=#0000ff]float[/COLOR] [COLOR=#001080]ramp_distance[/COLOR][[COLOR=#098658]3[/COLOR]];
  [COLOR=#0000ff]float[/COLOR] [COLOR=#001080]upper_threshold[/COLOR][[COLOR=#098658]3[/COLOR]];
  [COLOR=#0000ff]float[/COLOR] [COLOR=#001080]lower_threshold[/COLOR][[COLOR=#098658]3[/COLOR]];
} [COLOR=#267f99]T_ramp_envelope[/COLOR];
[COLOR=#008000]//------------------------------------------------------------------------------[/COLOR]
[COLOR=#0000ff]typedef[/COLOR] [COLOR=#0000ff]struct[/COLOR]
{
  [COLOR=#0000ff]float[/COLOR] leadscrew_pitch;[COLOR=#008000]   // typically 3.0mm ballscrew[/COLOR]
  [COLOR=#0000ff]float[/COLOR] gear_ratio;[COLOR=#008000]        // typically 7.2:1 on the hercus lathe (timing belt ratio)[/COLOR]
  [COLOR=#0000ff]float[/COLOR] steps_rev;[COLOR=#008000]         // typically 1000 (base of 200 steps per rev)[/COLOR]
  [COLOR=#0000ff]float[/COLOR] distance_perstep;[COLOR=#008000]  // mm per step / inches per step.[/COLOR]
  [COLOR=#0000ff]float[/COLOR] offset_comp;[COLOR=#008000]       //[/COLOR]
  [COLOR=#0000ff]float[/COLOR] scale_comp;[COLOR=#008000]        //[/COLOR]
} [COLOR=#267f99]T_axis_cal[/COLOR];[COLOR=#008000]              //[/COLOR]
[COLOR=#008000]//------------------------------------------------------------------------------[/COLOR]
[COLOR=#008000]// A 'T_axis' is a collection of structured data sent to each axis over SPI_1.[/COLOR]
[COLOR=#0000ff]typedef[/COLOR] [COLOR=#0000ff]struct[/COLOR]
{
  [COLOR=#0000ff]char[/COLOR] [COLOR=#001080]name[/COLOR][NAME_WIDTH];[COLOR=#008000]      //[/COLOR]
  T_axis_class axis_class;[COLOR=#008000]    // type of axis ac_null, ac_dist, ac_speed, ac_angle, used to interpret T_axis data[/COLOR]
  T_axis_cal axis_cal;[COLOR=#008000]        // how to calibrate this axis (using distance, speed, angle)[/COLOR]
  [COLOR=#0000ff]float[/COLOR] current_position;[COLOR=#008000]     // position measurement units[/COLOR]
  [COLOR=#0000ff]int[/COLOR] current_step;[COLOR=#008000]           // position in 'steps'[/COLOR]
  [COLOR=#0000ff]float[/COLOR] move_speed;[COLOR=#008000]           //[/COLOR]
  [COLOR=#0000ff]float[/COLOR] traverse_speed;[COLOR=#008000]       //[/COLOR]
  [COLOR=#0000ff]float[/COLOR] acceleration_factor;[COLOR=#008000]  //[/COLOR]
} [COLOR=#267f99]T_axis[/COLOR];[COLOR=#008000]                     //[/COLOR]
[COLOR=#008000]//------------------------------------------------------------------------------[/COLOR]

[COLOR=#0000ff]typedef[/COLOR] [COLOR=#0000ff]struct[/COLOR]
{
  [COLOR=#0000ff]float[/COLOR] radius;
  [COLOR=#0000ff]float[/COLOR] height;
  [COLOR=#0000ff]float[/COLOR] [COLOR=#001080]xyz_offset[/COLOR][[COLOR=#098658]3[/COLOR]];
  [COLOR=#0000ff]float[/COLOR] [COLOR=#001080]xyz_comp[/COLOR][[COLOR=#098658]3[/COLOR]];
} [COLOR=#267f99]T_tool_params[/COLOR];
[COLOR=#008000]//------------------------------------------------------------------------------[/COLOR]
[COLOR=#0000ff]typedef[/COLOR] [COLOR=#0000ff]struct[/COLOR]
{
  [COLOR=#0000ff]char[/COLOR] [COLOR=#001080]name[/COLOR][NAME_WIDTH];
  T_tool_params params;
} [COLOR=#267f99]T_tool[/COLOR];
[COLOR=#008000]//------------------------------------------------------------------------------[/COLOR]
[COLOR=#0000ff]typedef[/COLOR] [COLOR=#0000ff]struct[/COLOR]
{
  [COLOR=#0000ff]char[/COLOR] [COLOR=#001080]name[/COLOR][NAME_WIDTH];[COLOR=#008000]           //[/COLOR]
  T_machine_state state;[COLOR=#008000]           // current machine state with boolean and bit fields[/COLOR]
  T_ramp_envelope ramp_envelope;[COLOR=#008000]   // how to describe a ramp speed envelope[/COLOR]
  T_axis [COLOR=#001080]axes[/COLOR][N_AXES];[COLOR=#008000]             // axis parameters[/COLOR]
  T_tool [COLOR=#001080]tools[/COLOR][N_TOOLS];[COLOR=#008000]           // array of tools (with tool parameters)[/COLOR]
  T_origin_pt [COLOR=#001080]origins[/COLOR][N_ORIGINS];[COLOR=#008000]  // array of relative origins - (offsets)[/COLOR]
  [COLOR=#0000ff]int[/COLOR] gcode;[COLOR=#008000]                       // current G code[/COLOR]
  [COLOR=#0000ff]int[/COLOR] mcode;[COLOR=#008000]                       // current M code[/COLOR]
  [COLOR=#0000ff]int[/COLOR] tool_index;[COLOR=#008000]                  //[/COLOR]
  [COLOR=#0000ff]int[/COLOR] origin_index;[COLOR=#008000]                //[/COLOR]
  [COLOR=#0000ff]int[/COLOR] dwell_time;[COLOR=#008000]                  //[/COLOR]
  [COLOR=#0000ff]float[/COLOR] spindle_speed;[COLOR=#008000]             //[/COLOR]
  [COLOR=#0000ff]float[/COLOR] surface_speed;[COLOR=#008000]             //[/COLOR]
  [COLOR=#0000ff]float[/COLOR] move_rate;[COLOR=#008000]                 //[/COLOR]
  [COLOR=#0000ff]float[/COLOR] traverse_rate;[COLOR=#008000]             //[/COLOR]
  [COLOR=#0000ff]float[/COLOR] feed_rate;[COLOR=#008000]                 //[/COLOR]
  [COLOR=#0000ff]float[/COLOR] [COLOR=#001080]xyz_position[/COLOR][[COLOR=#098658]3[/COLOR]];[COLOR=#008000]           // 3d 'xyz' position[/COLOR]
  [COLOR=#0000ff]float[/COLOR] [COLOR=#001080]xyz_target[/COLOR][[COLOR=#098658]3[/COLOR]];[COLOR=#008000]             //[/COLOR]
  [COLOR=#0000ff]float[/COLOR] [COLOR=#001080]abc_position[/COLOR][[COLOR=#098658]3[/COLOR]];[COLOR=#008000]           // 3d 'abc' position[/COLOR]
  [COLOR=#0000ff]float[/COLOR] [COLOR=#001080]abc_target[/COLOR][[COLOR=#098658]3[/COLOR]];[COLOR=#008000]             //[/COLOR]
  [COLOR=#0000ff]float[/COLOR] [COLOR=#001080]uvw_position[/COLOR][[COLOR=#098658]3[/COLOR]];[COLOR=#008000]           // 3d 'uvw' position[/COLOR]
  [COLOR=#0000ff]float[/COLOR] [COLOR=#001080]uvw_target[/COLOR][[COLOR=#098658]3[/COLOR]];[COLOR=#008000]             //[/COLOR]
} [COLOR=#267f99]T_machine[/COLOR];[COLOR=#008000]                       // the defintion of the 'machine' with axes and a host of variables[/COLOR]
[COLOR=#008000]//------------------------------------------------------------------------------[/COLOR]
[COLOR=#008000]// instances of typedef-ed types[/COLOR]
[COLOR=#008000]//------------------------------------------------------------------------------[/COLOR]
T_console_errors console_errors;
T_xml_errors xml_errors;
T_gcparser gc_parser;
T_event_queue event_queue;
T_machine machine;
[COLOR=#008000]//--------------------------------------------------------------------------------[/COLOR]
[COLOR=#008000]// module variables for message handling[/COLOR]
[COLOR=#008000]//--------------------------------------------------------------------------------[/COLOR]
[COLOR=#0000ff]int[/COLOR] rx_ctr;[COLOR=#008000]                                 // keep track of the length of a message.[/COLOR]
[COLOR=#0000ff]unsigned[/COLOR] [COLOR=#0000ff]char[/COLOR] [COLOR=#001080]rx_buffer[/COLOR][UART_BUFFER_SIZE];[COLOR=#008000]  // circular buffer, usually 1024 or 2048 chars (power of 2)[/COLOR]
[COLOR=#0000ff]unsigned[/COLOR] [COLOR=#0000ff]char[/COLOR] rx_char;[COLOR=#008000]                      // latest character read from the uart[/COLOR]
[COLOR=#0000ff]int[/COLOR] buffer_head = [COLOR=#098658]0[/COLOR];[COLOR=#008000]                        // pointer to last charcter of the message (usually the null terminator).[/COLOR]
[COLOR=#0000ff]int[/COLOR] buffer_tail = [COLOR=#098658]0[/COLOR];[COLOR=#008000]                        // pointer to last charcter of the message (usually the null terminator).[/COLOR]
[COLOR=#0000ff]int[/COLOR] line_count = [COLOR=#098658]0[/COLOR];[COLOR=#008000]                         // count of 'received lines' - the number of null terminated messages in circular buffer[/COLOR]
[COLOR=#0000ff]int[/COLOR] buffer_count = [COLOR=#098658]0[/COLOR];[COLOR=#008000]                       // chars in circular buffer.[/COLOR]
[COLOR=#008000]//------------------------------------------------------------------------------[/COLOR]
[COLOR=#008000]// local module variables[/COLOR]
[COLOR=#008000]//------------------------------------------------------------------------------[/COLOR]
[COLOR=#0000ff]int[/COLOR] LED = [COLOR=#098658]13[/COLOR];[COLOR=#008000]  // pin 13 is the orange LED[/COLOR]
[COLOR=#0000ff]char[/COLOR] [COLOR=#001080]block[/COLOR][[COLOR=#098658]256[/COLOR]];
[COLOR=#0000ff]char[/COLOR] [COLOR=#001080]cmdln[/COLOR][[COLOR=#098658]256[/COLOR]];
[COLOR=#008000]//------------------------------------------------------------------------------[/COLOR]
[COLOR=#008000]// kick-off code[/COLOR]
[COLOR=#008000]//------------------------------------------------------------------------------[/COLOR]
[COLOR=#0000ff]void[/COLOR] [COLOR=#795e26]setup[/COLOR]() {
  [COLOR=#795e26]pinMode[/COLOR](LED, OUTPUT);
  [COLOR=#001080]Serial[/COLOR].[COLOR=#795e26]begin[/COLOR]([COLOR=#098658]115200[/COLOR]);
  [COLOR=#001080]Serial1[/COLOR].[COLOR=#795e26]begin[/COLOR]([COLOR=#098658]115200[/COLOR], SERIAL_8N1);
  [COLOR=#001080]Serial1[/COLOR].[COLOR=#795e26]setRX[/COLOR]([COLOR=#098658]0[/COLOR]);
  [COLOR=#001080]Serial1[/COLOR].[COLOR=#795e26]setTX[/COLOR]([COLOR=#098658]1[/COLOR]);
  [COLOR=#001080]Serial1[/COLOR].[COLOR=#795e26]attachRts[/COLOR]([COLOR=#098658]2[/COLOR]);
  [COLOR=#795e26]event_queue_init[/COLOR]();[COLOR=#008000] // setup an event queue[/COLOR]
  [COLOR=#795e26]machine_init[/COLOR]();[COLOR=#008000]    // initliase the machine with 3 axes.[/COLOR]
}
[COLOR=#008000]//------------------------------------------------------------------------------[/COLOR]
[COLOR=#008000]// main loop()[/COLOR]
[COLOR=#008000]//------------------------------------------------------------------------------[/COLOR]
[COLOR=#0000ff]void[/COLOR] [COLOR=#795e26]loop[/COLOR]() {
  [COLOR=#795e26]serial1Event[/COLOR]();[COLOR=#008000]         // check for the arrival of any chars[/COLOR]
  [COLOR=#af00db]if[/COLOR] (line_count) {[COLOR=#008000]       // if we have a new line of chars terminated by CRLF[/COLOR]
    [COLOR=#795e26]buff_read[/COLOR](cmdln);[COLOR=#008000]     // read them out of the cirular buffer into a null terminated linear char array[/COLOR]
    [COLOR=#795e26]parse_command[/COLOR](cmdln);[COLOR=#008000] // parse this into commands data and hash [/COLOR]
    [COLOR=#795e26]blip_led[/COLOR]([COLOR=#098658]100[/COLOR]);[COLOR=#008000]        // this emulates a time delay/wait on the machine function (100us)[/COLOR]
  }
}
[COLOR=#008000]//--------------------------------------------------------------------------------[/COLOR]
[COLOR=#008000]// take the block of data in the xml markup and see what to do with it[/COLOR]
[COLOR=#008000]//--------------------------------------------------------------------------------[/COLOR]
[COLOR=#0000ff]char[/COLOR] [COLOR=#001080]cmd[/COLOR][[COLOR=#098658]32[/COLOR]];
[COLOR=#0000ff]char[/COLOR] [COLOR=#001080]data[/COLOR][[COLOR=#098658]256[/COLOR]];
[COLOR=#0000ff]char[/COLOR] [COLOR=#001080]hash[/COLOR][[COLOR=#098658]32[/COLOR]];
[COLOR=#0000ff]void[/COLOR] [COLOR=#795e26]parse_command[/COLOR]([COLOR=#0000ff]char[/COLOR] [COLOR=#0000ff]*[/COLOR][COLOR=#001080]commandline[/COLOR]) {
  [COLOR=#0000ff]int[/COLOR] command;
  [COLOR=#795e26]strcpy_xml_string[/COLOR]([COLOR=#a31515]"cmd"[/COLOR], commandline, cmd);
  [COLOR=#795e26]strcpy_xml_string[/COLOR]([COLOR=#a31515]"data"[/COLOR], commandline, data);
  [COLOR=#795e26]strcpy_xml_string[/COLOR]([COLOR=#a31515]"hash"[/COLOR], commandline, hash);
  command = [COLOR=#795e26]atol[/COLOR](cmd);
  [COLOR=#af00db]switch[/COLOR] (command) {
    [COLOR=#af00db]case[/COLOR] GET_EXEC_GCODE:
      {
        [COLOR=#795e26]unpack_gcode_block[/COLOR](data);
      }
      [COLOR=#af00db]break[/COLOR];
    [COLOR=#af00db]case[/COLOR] GET_PING_REPLY:
      {
        [COLOR=#795e26]host_reply[/COLOR](GET_PING_REPLY, [COLOR=#a31515]"1234"[/COLOR]);
      }
      [COLOR=#af00db]break[/COLOR];
    [COLOR=#af00db]case[/COLOR] GET_MACHINE_POSITION_XYZ:
      {
        [COLOR=#795e26]host_reply[/COLOR](GET_MACHINE_POSITION_XYZ, [COLOR=#a31515]"<xyz>1.01,2.03,4.04</xyz>"[/COLOR]);
      }
      [COLOR=#af00db]break[/COLOR];
  }
}
[COLOR=#008000]//------------------------------------------------------------------------------[/COLOR]
[COLOR=#008000]// gen_hash() generates the 'unique' hash of an argument string.[/COLOR]
[COLOR=#008000]// Note: [/COLOR]
[COLOR=#008000]// This is a very simple integrity check and, over time, may have collisions (duplicates) or repeats, if the string is long enough.[/COLOR]
[COLOR=#008000]// However, each hash is 'unique' to the current buffer and, very likely, any others in close time proximity.[/COLOR]
[COLOR=#008000]// It indicates the integrity of a particular message using a 16 bit binary number (65536 different values).[/COLOR]
[COLOR=#008000]//------------------------------------------------------------------------------[/COLOR]
[COLOR=#0000ff]unsigned[/COLOR] [COLOR=#0000ff]int[/COLOR] [COLOR=#795e26]gen_hash[/COLOR]([COLOR=#0000ff]const[/COLOR] [COLOR=#0000ff]char[/COLOR] [COLOR=#0000ff]*[/COLOR][COLOR=#001080]cp[/COLOR]) {
  [COLOR=#0000ff]unsigned[/COLOR] [COLOR=#0000ff]long[/COLOR] [COLOR=#0000ff]int[/COLOR] uhash = [COLOR=#098658]5381[/COLOR];[COLOR=#008000]  // seed the hash - although we use a 32 bit integer, we are only interested in the right most 16  bits[/COLOR]
  [COLOR=#af00db]while[/COLOR] (*cp) {
    uhash = [COLOR=#098658]33[/COLOR] * uhash ^ ([COLOR=#0000ff]unsigned[/COLOR] [COLOR=#0000ff]char[/COLOR])*cp++;[COLOR=#008000]  // accumulate hash value of the string (this algorithm was found online and is plagiarised here).[/COLOR]
    uhash &= [COLOR=#098658]0x0000ffff[/COLOR];[COLOR=#008000]                        // limit result to 16 bits[/COLOR]
  }
  [COLOR=#af00db]return[/COLOR] (uhash);[COLOR=#008000]  // return the 'hash value' of the argument string '*cp' as the low 16 bits of a 32 bit integer.[/COLOR]
}
[COLOR=#008000]//------------------------------------------------------------------------------[/COLOR]
[COLOR=#008000]// host_reply() appropriately formats a reply to the hosting PC.[/COLOR]
[COLOR=#008000]// Two argument fields are supplied.[/COLOR]
[COLOR=#008000]// a) <cmd>3067</cmd> an integer value. 'cmd' mirrors the sent command constant, to which we are replying.[/COLOR]
[COLOR=#008000]// b) <data>345452</data>, a string value. 'data' is the replied data value as a string.[/COLOR]
[COLOR=#008000]// The xml tag 'data' may contain a parseable string with separators. Example: <data>f1,f2,f3,f4</data>[/COLOR]
[COLOR=#008000]// This procedure concatenates a 'hash' value as an itegrity check. Example: <hash>30778</hash>[/COLOR]
[COLOR=#008000]//------------------------------------------------------------------------------[/COLOR]
[COLOR=#0000ff]char[/COLOR] [COLOR=#001080]msgbuff[/COLOR][[COLOR=#098658]384[/COLOR]];[COLOR=#008000]  // these are global variables. If there are too many large local variables, we risk[/COLOR]
[COLOR=#0000ff]char[/COLOR] [COLOR=#001080]hashbuff[/COLOR][[COLOR=#098658]64[/COLOR]];[COLOR=#008000]  // running out of stack cpace. i.e. no 'malloc()', just statically allocated globals.[/COLOR]
[COLOR=#0000ff]void[/COLOR] [COLOR=#795e26]host_reply[/COLOR]([COLOR=#0000ff]int[/COLOR] [COLOR=#001080]cmd[/COLOR], [COLOR=#0000ff]const[/COLOR] [COLOR=#0000ff]char[/COLOR] [COLOR=#0000ff]*[/COLOR][COLOR=#001080]data[/COLOR]) {
  [COLOR=#795e26]sprintf[/COLOR](msgbuff, [COLOR=#a31515]"<msg><cmd>[/COLOR][COLOR=#001080]%d[/COLOR][COLOR=#a31515]</cmd><data>[/COLOR][COLOR=#001080]%s[/COLOR][COLOR=#a31515]</data></msg>"[/COLOR], cmd, data);[COLOR=#008000]  // format the reply message[/COLOR]
  [COLOR=#795e26]sprintf[/COLOR](hashbuff, [COLOR=#a31515]"<hash>[/COLOR][COLOR=#001080]%d[/COLOR][COLOR=#a31515]</hash>"[/COLOR], [COLOR=#795e26]gen_hash[/COLOR](msgbuff));[COLOR=#008000]                 // take its 'hash'[/COLOR]
  [COLOR=#795e26]strcat[/COLOR](msgbuff, hashbuff);[COLOR=#008000]                                               // append the hash value to the message[/COLOR]
  [COLOR=#001080]Serial1[/COLOR].[COLOR=#795e26]println[/COLOR](msgbuff);[COLOR=#008000]                                                // output the message with a 'LF + CR' pair[/COLOR]
}
[COLOR=#008000]//------------------------------------------------------------------------------[/COLOR]
[COLOR=#008000]// checking and reading the serial event data attached to serial1[/COLOR]
[COLOR=#008000]//------------------------------------------------------------------------------[/COLOR]
[COLOR=#0000ff]void[/COLOR] [COLOR=#795e26]serial1Event[/COLOR]() {
  [COLOR=#0000ff]char[/COLOR] rx_char;
  [COLOR=#af00db]while[/COLOR] ([COLOR=#001080]Serial1[/COLOR].[COLOR=#795e26]available[/COLOR]()) {
    rx_char = ([COLOR=#0000ff]char[/COLOR])[COLOR=#001080]Serial1[/COLOR].[COLOR=#795e26]read[/COLOR]();
    [COLOR=#af00db]if[/COLOR] ([COLOR=#795e26]isgraph[/COLOR](rx_char) || (rx_char == [COLOR=#098658]32[/COLOR]) || (rx_char == [COLOR=#098658]10[/COLOR]))[COLOR=#008000]                  // throw away 'funny' characters i.e. only allow printable chars or a new-line.[/COLOR]
    {[COLOR=#008000]                                                                            //[/COLOR]
      [COLOR=#001080]rx_buffer[/COLOR][buffer_head++] = rx_char;[COLOR=#008000]                                        // store rx_char into the circular buffer and increment the buffer head[/COLOR]
      buffer_head &= (UART_BUFFER_SIZE - [COLOR=#098658]1[/COLOR]);[COLOR=#008000]                                     // perform 'rollover' arithmetic on the buffer head index[/COLOR]
      [COLOR=#af00db]if[/COLOR] (++rx_ctr > COMMAND_LINE_LENGTH - [COLOR=#098658]4[/COLOR]) [COLOR=#001080]console_errors[/COLOR].[COLOR=#001080]line_too_long[/COLOR] = [COLOR=#098658]1[/COLOR];[COLOR=#008000]  // note if the command length is longer than 254 chars[/COLOR]
      [COLOR=#af00db]if[/COLOR] (rx_char == [COLOR=#a31515]'[/COLOR][COLOR=#ee0000]\n[/COLOR][COLOR=#a31515]'[/COLOR])[COLOR=#008000]                                                       // is the rx_char a new line? end of frame....[/COLOR]
      {[COLOR=#008000]                                                                          //[/COLOR]
        buffer_head--;[COLOR=#008000]                                                           // prepare to overwrite the LF char with a null.[/COLOR]
        buffer_head &= (UART_BUFFER_SIZE - [COLOR=#098658]1[/COLOR]);[COLOR=#008000]                                   // perform circular 'rollover' arithemetic on the buffer_head index[/COLOR]
        [COLOR=#001080]rx_buffer[/COLOR][buffer_head] = [COLOR=#a31515]'[/COLOR][COLOR=#ee0000]\0[/COLOR][COLOR=#a31515]'[/COLOR];[COLOR=#008000]                                           // overwrite the LF char with a null[/COLOR]
        rx_ctr = [COLOR=#098658]0[/COLOR];[COLOR=#008000]                                                              // zero the rx_ctr ( the received string length)[/COLOR]
        line_count++;[COLOR=#008000]                                                            // signal that there is another command in the buffer[/COLOR]
      }[COLOR=#008000]                                                                          //[/COLOR]
      buffer_count = [COLOR=#795e26]input_buffer_charcount[/COLOR]();[COLOR=#008000]                                   // input to manage buffer handshake[/COLOR]
[COLOR=#008000]                                                                                 //      if (buffer_count > CHAR_COUNT_UPPER_THRESHOLD) RTS_OFF;               // disable communication if buffer is "near full".[/COLOR]
    }
  }
}
[COLOR=#008000]//------------------------------------------------------------------------------[/COLOR]
[COLOR=#008000]// input_buffer_charcount()[/COLOR]
[COLOR=#008000]// Returns the number of characters in the circular receive buffer.[/COLOR]
[COLOR=#008000]//------------------------------------------------------------------------------[/COLOR]
[COLOR=#0000ff]unsigned[/COLOR] [COLOR=#0000ff]int[/COLOR] [COLOR=#795e26]input_buffer_charcount[/COLOR]([COLOR=#0000ff]void[/COLOR]) {
  [COLOR=#0000ff]unsigned[/COLOR] [COLOR=#0000ff]int[/COLOR] char_count;
  [COLOR=#af00db]if[/COLOR] (buffer_head >= buffer_tail) char_count = buffer_head - buffer_tail;
  [COLOR=#af00db]else[/COLOR] char_count = (UART_BUFFER_SIZE - buffer_tail) + buffer_head;
  [COLOR=#af00db]return[/COLOR] (char_count);
}
[COLOR=#008000]//------------------------------------------------------------------------------[/COLOR]
[COLOR=#008000]// buff_read()....[/COLOR]
[COLOR=#008000]// :Copies the source strs from the input circular buffer to the target linear buffer (the *s argument).[/COLOR]
[COLOR=#008000]// :Expects 'null' terminated strings in the rx_buffer circular buffer.[/COLOR]
[COLOR=#008000]// :Then cycles around the buffer to copy out a string until a null is found.[/COLOR]
[COLOR=#008000]// :Also returns a pointer to the start of the source string.[/COLOR]
[COLOR=#008000]//------------------------------------------------------------------------------[/COLOR]
[COLOR=#0000ff]char[/COLOR] [COLOR=#0000ff]*[/COLOR][COLOR=#795e26]buff_read[/COLOR]([COLOR=#0000ff]char[/COLOR] [COLOR=#0000ff]*[/COLOR][COLOR=#001080]s[/COLOR]) {
  [COLOR=#0000ff]register[/COLOR] [COLOR=#0000ff]char[/COLOR] *c = s;[COLOR=#008000]                     // make a local copy of the target pointer.[/COLOR]
  [COLOR=#af00db]while[/COLOR] ([COLOR=#001080]rx_buffer[/COLOR][buffer_tail])[COLOR=#008000]            // examine the the string until 'null' is found[/COLOR]
  {[COLOR=#008000]                                         // register pointer 'c' points to the far string.[/COLOR]
    *c++ = [COLOR=#001080]rx_buffer[/COLOR][buffer_tail++];[COLOR=#008000]        //[/COLOR]
    buffer_tail &= (UART_BUFFER_SIZE - [COLOR=#098658]1[/COLOR]);[COLOR=#008000]  // RULE: for this to work, UART_BUFFER_SIZE must be an integral power of 2[/COLOR]
  }[COLOR=#008000]                                         // eg, 256, 512, 1024 etc.otherwise you need to do some pointer arithmetic[/COLOR]
  *c = [COLOR=#a31515]'[/COLOR][COLOR=#ee0000]\0[/COLOR][COLOR=#a31515]'[/COLOR];[COLOR=#008000]                                // Null terminate the copied string just in case.[/COLOR]
  [COLOR=#af00db]if[/COLOR] (line_count) line_count--;[COLOR=#008000]             // if we have a non zero line_count, decrement the count.[/COLOR]
  buffer_count = [COLOR=#795e26]input_buffer_charcount[/COLOR]();
[COLOR=#008000]  // if (buffer_count < CHAR_COUNT_LOWER_THRESHOLD) RTS_ON;[/COLOR]
  [COLOR=#af00db]return[/COLOR] (s);[COLOR=#008000]  // return the pointer to the string, as per standard str() functions[/COLOR]
}
[COLOR=#008000]//------------------------------------------------------------------------------[/COLOR]
[COLOR=#008000]// blip_led()[/COLOR]
[COLOR=#008000]// :holds the led on pin 13 'ON' for 'duration' microseconds.[/COLOR]
[COLOR=#008000]//------------------------------------------------------------------------------[/COLOR]
[COLOR=#0000ff]void[/COLOR] [COLOR=#795e26]blip_led[/COLOR]([COLOR=#0000ff]int[/COLOR] [COLOR=#001080]duration[/COLOR]) {
  [COLOR=#795e26]digitalWrite[/COLOR](LED, HIGH);
  [COLOR=#795e26]delayMicroseconds[/COLOR](duration);
  [COLOR=#795e26]digitalWrite[/COLOR](LED, LOW);
}
[COLOR=#008000]//------------------------------------------------------------------------------[/COLOR]
[COLOR=#008000]// convert_string()[/COLOR]
[COLOR=#008000]// : copies a C++ string into a normal char[] array and null terminates it.[/COLOR]
[COLOR=#008000]//------------------------------------------------------------------------------[/COLOR]
[COLOR=#0000ff]void[/COLOR] [COLOR=#795e26]convert_string[/COLOR]([COLOR=#267f99]String[/COLOR] [COLOR=#001080]inp[/COLOR], [COLOR=#0000ff]char[/COLOR] [COLOR=#0000ff]*[/COLOR][COLOR=#001080]target[/COLOR]) {
  [COLOR=#0000ff]int[/COLOR] i;
  [COLOR=#0000ff]int[/COLOR] len = [COLOR=#001080]inp[/COLOR].[COLOR=#795e26]length[/COLOR]();
  [COLOR=#af00db]for[/COLOR] (i = [COLOR=#098658]0[/COLOR]; i < len; i++) {
    *target++ = [COLOR=#001080]inp[/COLOR][i];
  }
  *target = [COLOR=#a31515]'[/COLOR][COLOR=#ee0000]\0[/COLOR][COLOR=#a31515]'[/COLOR];
}
[COLOR=#008000]//------------------------------------------------------------------------------[/COLOR]
[COLOR=#008000]// Non invasive version of 'get_xml_string()'[/COLOR]
[COLOR=#008000]// strcpy_xml_string copies a null terminated substring that exists between the outer xml tags[/COLOR]
[COLOR=#008000]// e.g. // from "<xmltag>this string will be returned</xmltag>"" it returns "this string will be returned" as a null terminated string.[/COLOR]
[COLOR=#008000]// This function does not affect the source string.[/COLOR]
[COLOR=#008000]// The tag or token, can be a string of any printable alphabetical ascii no more than 16 characters long.[/COLOR]
[COLOR=#008000]// If the "<tag>"" doesn't exist or is not bounded by a complementary "</tag>", the function returns a '\0' delimiter to *tgt pointer of the target string[/COLOR]
[COLOR=#008000]// TO DO: Limit the max number of chars allowrd to be moved (like strncpy).[/COLOR]
[COLOR=#008000]//------------------------------------------------------------------------------[/COLOR]
[COLOR=#0000ff]void[/COLOR] [COLOR=#795e26]strcpy_xml_string[/COLOR]([COLOR=#0000ff]const[/COLOR] [COLOR=#0000ff]char[/COLOR] [COLOR=#0000ff]*[/COLOR][COLOR=#001080]tag[/COLOR], [COLOR=#0000ff]char[/COLOR] [COLOR=#0000ff]*[/COLOR][COLOR=#001080]src[/COLOR], [COLOR=#0000ff]char[/COLOR] [COLOR=#0000ff]*[/COLOR][COLOR=#001080]tgt[/COLOR]) {
  [COLOR=#0000ff]char[/COLOR] [COLOR=#001080]start_tag[/COLOR][MAX_XML_TAG + [COLOR=#098658]2[/COLOR]];[COLOR=#008000]  // local storage[/COLOR]
  [COLOR=#0000ff]char[/COLOR] [COLOR=#001080]end_tag[/COLOR][MAX_XML_TAG + [COLOR=#098658]3[/COLOR]];[COLOR=#008000]    // for tag braces "<>" and "</>" plus the tag string itself[/COLOR]
  [COLOR=#0000ff]char[/COLOR] *st;[COLOR=#008000]                         // pointer to start tag <>[/COLOR]
  [COLOR=#0000ff]char[/COLOR] *et;[COLOR=#008000]                         // pointer to end tag   </>[/COLOR]
  [COLOR=#0000ff]char[/COLOR] *xml_body_start;[COLOR=#008000]             // pointer to start of xml body[/COLOR]
  [COLOR=#0000ff]char[/COLOR] *xml_body_end;[COLOR=#008000]               // pointer to end of xml body[/COLOR]
  st = start_tag;[COLOR=#008000]                   // assign pointers to buffers[/COLOR]
  et = end_tag;[COLOR=#008000]                     //[/COLOR]
  [COLOR=#795e26]strcpy[/COLOR](st, [COLOR=#a31515]"<"[/COLOR]);[COLOR=#008000]                  // construct both the start and end tags[/COLOR]
  [COLOR=#795e26]strcat[/COLOR](st, tag);
  [COLOR=#795e26]strcat[/COLOR](st, [COLOR=#a31515]">"[/COLOR]);
  [COLOR=#795e26]strcpy[/COLOR](et, [COLOR=#a31515]"</"[/COLOR]);
  [COLOR=#795e26]strcat[/COLOR](et, tag);
  [COLOR=#795e26]strcat[/COLOR](et, [COLOR=#a31515]">"[/COLOR]);
  [COLOR=#af00db]if[/COLOR] (([COLOR=#795e26]strstr[/COLOR](src, st) != [COLOR=#0000ff]NULL[/COLOR]) && ([COLOR=#795e26]strstr[/COLOR](src, et) != [COLOR=#0000ff]NULL[/COLOR]))[COLOR=#008000]  // verify that both tags are present in the arg *src string.[/COLOR]
  {
    xml_body_start = [COLOR=#795e26]strstr[/COLOR](src, st) + [COLOR=#795e26]strlen[/COLOR](st);[COLOR=#008000]  // point to xml body start.[/COLOR]
    xml_body_end = [COLOR=#795e26]strstr[/COLOR](xml_body_start, et);[COLOR=#008000]      // point to xml body end.[/COLOR]
    [COLOR=#af00db]while[/COLOR] (xml_body_start != xml_body_end)[COLOR=#008000]          // perform a 'strcpy' on the partial substring[/COLOR]
    {
      *tgt++ = *xml_body_start++;
    }
  }
  *tgt = [COLOR=#a31515]'[/COLOR][COLOR=#ee0000]\0[/COLOR][COLOR=#a31515]'[/COLOR];[COLOR=#008000]  // always set NULL at the end. If we fail to find a string, it sets the first element of 'tgt[0]' to NULL.[/COLOR]
}
[COLOR=#008000]//------------------------------------------------------------------------------[/COLOR]
[COLOR=#008000]// GCode parser section.[/COLOR]
[COLOR=#008000]//------------------------------------------------------------------------------[/COLOR]
[COLOR=#0000ff]void[/COLOR] [COLOR=#795e26]unpack_gcode_block[/COLOR]([COLOR=#0000ff]char[/COLOR] [COLOR=#0000ff]*[/COLOR][COLOR=#001080]s[/COLOR]) {
  [COLOR=#0000ff]int[/COLOR] i;
  T_event event;
  [COLOR=#795e26]strncpy[/COLOR]([COLOR=#001080]gc_parser[/COLOR].[COLOR=#001080]gc_codeblock[/COLOR], s, [COLOR=#098658]256[/COLOR]);
  [COLOR=#795e26]extract_gcode_comments[/COLOR]([COLOR=#001080]gc_parser[/COLOR].[COLOR=#001080]gc_codeblock[/COLOR], [COLOR=#001080]gc_parser[/COLOR].[COLOR=#001080]comments[/COLOR]);
  [COLOR=#795e26]strip_white_space[/COLOR]([COLOR=#001080]gc_parser[/COLOR].[COLOR=#001080]gc_codestrings[/COLOR], [COLOR=#001080]gc_parser[/COLOR].[COLOR=#001080]gc_codeblock[/COLOR]);
  [COLOR=#795e26]extract_gcode_commands[/COLOR](&gc_parser);
  [COLOR=#795e26]clear_event[/COLOR](&event);
  [COLOR=#001080]gc_parser[/COLOR].[COLOR=#001080]gc_errors[/COLOR].[COLOR=#001080]bits[/COLOR] = [COLOR=#098658]0[/COLOR];
  [COLOR=#001080]gc_parser[/COLOR].[COLOR=#001080]g[/COLOR] = [COLOR=#098658]0[/COLOR];[COLOR=#008000]                          // G command count set to 0. Note that a maximum of 4 G values can be set in one gcode block.[/COLOR]
  [COLOR=#001080]gc_parser[/COLOR].[COLOR=#001080]m[/COLOR] = [COLOR=#098658]0[/COLOR];[COLOR=#008000]                          // M command count set to 0. Note that a maximum of 4 M values can be set in one gcode block.[/COLOR]
  [COLOR=#795e26]strcpy[/COLOR]([COLOR=#001080]gc_parser[/COLOR].[COLOR=#001080]last_error_desc[/COLOR], [COLOR=#a31515]"[/COLOR][COLOR=#ee0000]\0[/COLOR][COLOR=#a31515]"[/COLOR]);[COLOR=#008000]  // put a null at the first element of the error description[/COLOR]

  [COLOR=#af00db]for[/COLOR] (i = [COLOR=#098658]0[/COLOR]; i < [COLOR=#001080]gc_parser[/COLOR].[COLOR=#001080]argc[/COLOR]; i++) {
    [COLOR=#795e26]eval_parameter_string[/COLOR]([COLOR=#001080]gc_parser[/COLOR].[COLOR=#001080]args[/COLOR][i], &event);[COLOR=#008000]  // build event parameters by rippling through the gcode block[/COLOR]
  }
  [COLOR=#af00db]if[/COLOR] ([COLOR=#001080]gc_parser[/COLOR].[COLOR=#001080]gc_errors[/COLOR].[COLOR=#001080]bits[/COLOR] == [COLOR=#098658]0[/COLOR]) [COLOR=#001080]event_queue[/COLOR].[COLOR=#795e26]add[/COLOR](&event);[COLOR=#008000]  // if there are no errors, add the event to the event_queue[/COLOR]
}
[COLOR=#008000]//------------------------------------------------------------------------------[/COLOR]
[COLOR=#008000]// Evaluates each parameter in a GCode block[/COLOR]
[COLOR=#008000]//------------------------------------------------------------------------------[/COLOR]
[COLOR=#0000ff]void[/COLOR] [COLOR=#795e26]eval_parameter_string[/COLOR]([COLOR=#0000ff]char[/COLOR] [COLOR=#0000ff]*[/COLOR][COLOR=#001080]s[/COLOR], [COLOR=#267f99]T_event[/COLOR] [COLOR=#0000ff]*[/COLOR][COLOR=#001080]evt[/COLOR]) {
  [COLOR=#0000ff]char[/COLOR] *c;
  c = s;
  [COLOR=#af00db]while[/COLOR] (*c) {
    [COLOR=#af00db]if[/COLOR] ([COLOR=#795e26]isalpha[/COLOR](*c)) {
      [COLOR=#af00db]switch[/COLOR] (*c) {
        [COLOR=#af00db]case[/COLOR] [COLOR=#a31515]'A'[/COLOR]:
          {
            [COLOR=#001080]evt[/COLOR]->[COLOR=#001080]abc[/COLOR][[COLOR=#098658]0[/COLOR]] = [COLOR=#795e26]safe_float[/COLOR](c + [COLOR=#098658]1[/COLOR]);
            [COLOR=#001080]evt[/COLOR]->[COLOR=#001080]field_flags[/COLOR].[COLOR=#001080]a_changed[/COLOR] = [COLOR=#098658]1[/COLOR];
          }
          [COLOR=#af00db]break[/COLOR];
        [COLOR=#af00db]case[/COLOR] [COLOR=#a31515]'B'[/COLOR]:
          {
            [COLOR=#001080]evt[/COLOR]->[COLOR=#001080]abc[/COLOR][[COLOR=#098658]1[/COLOR]] = [COLOR=#795e26]safe_float[/COLOR](c + [COLOR=#098658]1[/COLOR]);
            [COLOR=#001080]evt[/COLOR]->[COLOR=#001080]field_flags[/COLOR].[COLOR=#001080]b_changed[/COLOR] = [COLOR=#098658]1[/COLOR];
          }
          [COLOR=#af00db]break[/COLOR];
        [COLOR=#af00db]case[/COLOR] [COLOR=#a31515]'C'[/COLOR]:
          {
            [COLOR=#001080]evt[/COLOR]->[COLOR=#001080]abc[/COLOR][[COLOR=#098658]2[/COLOR]] = [COLOR=#795e26]safe_float[/COLOR](c + [COLOR=#098658]1[/COLOR]);
            [COLOR=#001080]evt[/COLOR]->[COLOR=#001080]field_flags[/COLOR].[COLOR=#001080]c_changed[/COLOR] = [COLOR=#098658]1[/COLOR];
          }
          [COLOR=#af00db]break[/COLOR];
        [COLOR=#af00db]case[/COLOR] [COLOR=#a31515]'D'[/COLOR]:
          {
            [COLOR=#001080]evt[/COLOR]->[COLOR=#001080]field_flags[/COLOR].[COLOR=#001080]d_changed[/COLOR] = [COLOR=#098658]1[/COLOR];
          }
          [COLOR=#af00db]break[/COLOR];
        [COLOR=#af00db]case[/COLOR] [COLOR=#a31515]'E'[/COLOR]:
          {
            [COLOR=#001080]evt[/COLOR]->[COLOR=#001080]field_flags[/COLOR].[COLOR=#001080]e_changed[/COLOR] = [COLOR=#098658]1[/COLOR];
          }
          [COLOR=#af00db]break[/COLOR];
        [COLOR=#af00db]case[/COLOR] [COLOR=#a31515]'F'[/COLOR]:
          {
            [COLOR=#001080]evt[/COLOR]->[COLOR=#001080]feed_rate[/COLOR] = [COLOR=#795e26]safe_float[/COLOR](c + [COLOR=#098658]1[/COLOR]);
            [COLOR=#001080]evt[/COLOR]->[COLOR=#001080]field_flags[/COLOR].[COLOR=#001080]f_changed[/COLOR] = [COLOR=#098658]1[/COLOR];
          }
          [COLOR=#af00db]break[/COLOR];
        [COLOR=#af00db]case[/COLOR] [COLOR=#a31515]'G'[/COLOR]:
          {
            [COLOR=#001080]evt[/COLOR]->[COLOR=#001080]gcode_param[/COLOR][[COLOR=#001080]gc_parser[/COLOR].[COLOR=#001080]g[/COLOR]++] = [COLOR=#795e26]safe_int[/COLOR](c + [COLOR=#098658]1[/COLOR]);
            [COLOR=#001080]evt[/COLOR]->[COLOR=#001080]field_flags[/COLOR].[COLOR=#001080]g_changed[/COLOR] = [COLOR=#098658]1[/COLOR];
          }
          [COLOR=#af00db]break[/COLOR];
        [COLOR=#af00db]case[/COLOR] [COLOR=#a31515]'H'[/COLOR]:
          {
            [COLOR=#001080]evt[/COLOR]->[COLOR=#001080]field_flags[/COLOR].[COLOR=#001080]h_changed[/COLOR] = [COLOR=#098658]1[/COLOR];
          }
          [COLOR=#af00db]break[/COLOR];
        [COLOR=#af00db]case[/COLOR] [COLOR=#a31515]'I'[/COLOR]:
          {
            [COLOR=#001080]evt[/COLOR]->[COLOR=#001080]field_flags[/COLOR].[COLOR=#001080]i_changed[/COLOR] = [COLOR=#098658]1[/COLOR];
          }
          [COLOR=#af00db]break[/COLOR];
        [COLOR=#af00db]case[/COLOR] [COLOR=#a31515]'J'[/COLOR]:
          {
            [COLOR=#001080]evt[/COLOR]->[COLOR=#001080]field_flags[/COLOR].[COLOR=#001080]j_changed[/COLOR] = [COLOR=#098658]1[/COLOR];
          }
          [COLOR=#af00db]break[/COLOR];
        [COLOR=#af00db]case[/COLOR] [COLOR=#a31515]'K'[/COLOR]:
          {
            [COLOR=#001080]evt[/COLOR]->[COLOR=#001080]field_flags[/COLOR].[COLOR=#001080]k_changed[/COLOR] = [COLOR=#098658]1[/COLOR];
          }
          [COLOR=#af00db]break[/COLOR];
        [COLOR=#af00db]case[/COLOR] [COLOR=#a31515]'L'[/COLOR]:
          {
            [COLOR=#001080]evt[/COLOR]->[COLOR=#001080]field_flags[/COLOR].[COLOR=#001080]l_changed[/COLOR] = [COLOR=#098658]1[/COLOR];
          }
          [COLOR=#af00db]break[/COLOR];
        [COLOR=#af00db]case[/COLOR] [COLOR=#a31515]'M'[/COLOR]:
          {
            [COLOR=#001080]evt[/COLOR]->[COLOR=#001080]mcode_param[/COLOR][[COLOR=#001080]gc_parser[/COLOR].[COLOR=#001080]m[/COLOR]++] = [COLOR=#795e26]safe_int[/COLOR](c + [COLOR=#098658]1[/COLOR]);
            [COLOR=#001080]evt[/COLOR]->[COLOR=#001080]field_flags[/COLOR].[COLOR=#001080]m_changed[/COLOR] = [COLOR=#098658]1[/COLOR];
          }
          [COLOR=#af00db]break[/COLOR];
        [COLOR=#af00db]case[/COLOR] [COLOR=#a31515]'N'[/COLOR]:
          {
            [COLOR=#001080]evt[/COLOR]->[COLOR=#001080]line_number[/COLOR] = [COLOR=#795e26]safe_int[/COLOR](c + [COLOR=#098658]1[/COLOR]);
            [COLOR=#001080]evt[/COLOR]->[COLOR=#001080]field_flags[/COLOR].[COLOR=#001080]n_changed[/COLOR] = [COLOR=#098658]1[/COLOR];
          }
          [COLOR=#af00db]break[/COLOR];
        [COLOR=#af00db]case[/COLOR] [COLOR=#a31515]'O'[/COLOR]:
          {
            [COLOR=#001080]evt[/COLOR]->[COLOR=#001080]field_flags[/COLOR].[COLOR=#001080]o_changed[/COLOR] = [COLOR=#098658]1[/COLOR];
          }
          [COLOR=#af00db]break[/COLOR];
        [COLOR=#af00db]case[/COLOR] [COLOR=#a31515]'P'[/COLOR]:
          {
            [COLOR=#001080]evt[/COLOR]->[COLOR=#001080]dwell_time[/COLOR] = [COLOR=#795e26]safe_int[/COLOR](c + [COLOR=#098658]1[/COLOR]);
            [COLOR=#001080]evt[/COLOR]->[COLOR=#001080]field_flags[/COLOR].[COLOR=#001080]p_changed[/COLOR] = [COLOR=#098658]1[/COLOR];
          }
          [COLOR=#af00db]break[/COLOR];
        [COLOR=#af00db]case[/COLOR] [COLOR=#a31515]'Q'[/COLOR]:
          {
            [COLOR=#001080]evt[/COLOR]->[COLOR=#001080]field_flags[/COLOR].[COLOR=#001080]q_changed[/COLOR] = [COLOR=#098658]1[/COLOR];
          }
          [COLOR=#af00db]break[/COLOR];
        [COLOR=#af00db]case[/COLOR] [COLOR=#a31515]'R'[/COLOR]:
          {
            [COLOR=#001080]evt[/COLOR]->[COLOR=#001080]radius[/COLOR] = [COLOR=#795e26]safe_float[/COLOR](c + [COLOR=#098658]1[/COLOR]);
            [COLOR=#001080]evt[/COLOR]->[COLOR=#001080]field_flags[/COLOR].[COLOR=#001080]r_changed[/COLOR] = [COLOR=#098658]1[/COLOR];
          }
          [COLOR=#af00db]break[/COLOR];
        [COLOR=#af00db]case[/COLOR] [COLOR=#a31515]'S'[/COLOR]:
          {
            [COLOR=#001080]evt[/COLOR]->[COLOR=#001080]speed[/COLOR] = [COLOR=#795e26]safe_float[/COLOR](c + [COLOR=#098658]1[/COLOR]);
            [COLOR=#001080]evt[/COLOR]->[COLOR=#001080]field_flags[/COLOR].[COLOR=#001080]s_changed[/COLOR] = [COLOR=#098658]1[/COLOR];
          }
          [COLOR=#af00db]break[/COLOR];
        [COLOR=#af00db]case[/COLOR] [COLOR=#a31515]'T'[/COLOR]:
          {
            [COLOR=#001080]evt[/COLOR]->[COLOR=#001080]tool_select[/COLOR] = [COLOR=#795e26]safe_int[/COLOR](c + [COLOR=#098658]1[/COLOR]);
            [COLOR=#001080]evt[/COLOR]->[COLOR=#001080]field_flags[/COLOR].[COLOR=#001080]t_changed[/COLOR] = [COLOR=#098658]1[/COLOR];
          }
          [COLOR=#af00db]break[/COLOR];
        [COLOR=#af00db]case[/COLOR] [COLOR=#a31515]'U'[/COLOR]:
          {
            [COLOR=#001080]evt[/COLOR]->[COLOR=#001080]uvw[/COLOR][[COLOR=#098658]0[/COLOR]] = [COLOR=#795e26]safe_float[/COLOR](c + [COLOR=#098658]1[/COLOR]);
            [COLOR=#001080]evt[/COLOR]->[COLOR=#001080]field_flags[/COLOR].[COLOR=#001080]u_changed[/COLOR] = [COLOR=#098658]1[/COLOR];
          }
          [COLOR=#af00db]break[/COLOR];
        [COLOR=#af00db]case[/COLOR] [COLOR=#a31515]'V'[/COLOR]:
          {
            [COLOR=#001080]evt[/COLOR]->[COLOR=#001080]uvw[/COLOR][[COLOR=#098658]1[/COLOR]] = [COLOR=#795e26]safe_float[/COLOR](c + [COLOR=#098658]1[/COLOR]);
            [COLOR=#001080]evt[/COLOR]->[COLOR=#001080]field_flags[/COLOR].[COLOR=#001080]v_changed[/COLOR] = [COLOR=#098658]1[/COLOR];
          }
          [COLOR=#af00db]break[/COLOR];
        [COLOR=#af00db]case[/COLOR] [COLOR=#a31515]'W'[/COLOR]:
          {
            [COLOR=#001080]evt[/COLOR]->[COLOR=#001080]uvw[/COLOR][[COLOR=#098658]2[/COLOR]] = [COLOR=#795e26]safe_float[/COLOR](c + [COLOR=#098658]1[/COLOR]);
            [COLOR=#001080]evt[/COLOR]->[COLOR=#001080]field_flags[/COLOR].[COLOR=#001080]w_changed[/COLOR] = [COLOR=#098658]1[/COLOR];
          }
          [COLOR=#af00db]break[/COLOR];
        [COLOR=#af00db]case[/COLOR] [COLOR=#a31515]'X'[/COLOR]:
          {
            [COLOR=#001080]evt[/COLOR]->[COLOR=#001080]xyz[/COLOR][[COLOR=#098658]0[/COLOR]] = [COLOR=#795e26]safe_float[/COLOR](c + [COLOR=#098658]1[/COLOR]);
            [COLOR=#001080]evt[/COLOR]->[COLOR=#001080]field_flags[/COLOR].[COLOR=#001080]x_changed[/COLOR] = [COLOR=#098658]1[/COLOR];
          }
          [COLOR=#af00db]break[/COLOR];
        [COLOR=#af00db]case[/COLOR] [COLOR=#a31515]'Y'[/COLOR]:
          {
            [COLOR=#001080]evt[/COLOR]->[COLOR=#001080]xyz[/COLOR][[COLOR=#098658]1[/COLOR]] = [COLOR=#795e26]safe_float[/COLOR](c + [COLOR=#098658]1[/COLOR]);
            [COLOR=#001080]evt[/COLOR]->[COLOR=#001080]field_flags[/COLOR].[COLOR=#001080]y_changed[/COLOR] = [COLOR=#098658]1[/COLOR];
          }
          [COLOR=#af00db]break[/COLOR];
        [COLOR=#af00db]case[/COLOR] [COLOR=#a31515]'Z'[/COLOR]:
          {
            [COLOR=#001080]evt[/COLOR]->[COLOR=#001080]xyz[/COLOR][[COLOR=#098658]2[/COLOR]] = [COLOR=#795e26]safe_float[/COLOR](c + [COLOR=#098658]1[/COLOR]);
            [COLOR=#001080]evt[/COLOR]->[COLOR=#001080]field_flags[/COLOR].[COLOR=#001080]z_changed[/COLOR] = [COLOR=#098658]1[/COLOR];
          }
          [COLOR=#af00db]break[/COLOR];
        [COLOR=#af00db]default[/COLOR]:
          {
            [COLOR=#001080]gc_parser[/COLOR].[COLOR=#001080]gc_errors[/COLOR].[COLOR=#001080]unknown_gc_token[/COLOR] = [COLOR=#098658]1[/COLOR];
            [COLOR=#795e26]gc_strerror[/COLOR]();
          };[COLOR=#008000]  // unknown gc token[/COLOR]
      }
    }
    c++;
  }
}
[COLOR=#008000]//------------------------------------------------------------------------------[/COLOR]
[COLOR=#008000]// Comment signifiers "%" or "//"  - all chars to the right of the token are treated as a comment[/COLOR]
[COLOR=#008000]// ...% This is a comment.[/COLOR]
[COLOR=#008000]// ...// This is a comment.[/COLOR]
[COLOR=#008000]// comment specifier "(" and ")" the field in between () is a comment[/COLOR]
[COLOR=#008000]// ...(This is a comment).[/COLOR]
[COLOR=#008000]// comment specifier "{" and "}" the field in between {} is a comment[/COLOR]
[COLOR=#008000]// ...{This is a comment}.[/COLOR]
[COLOR=#008000]//------------------------------------------------------------------------------[/COLOR]
[COLOR=#0000ff]int[/COLOR] [COLOR=#795e26]extract_gcode_comments[/COLOR]([COLOR=#0000ff]char[/COLOR] [COLOR=#0000ff]*[/COLOR][COLOR=#001080]source[/COLOR], [COLOR=#0000ff]char[/COLOR] [COLOR=#0000ff]*[/COLOR][COLOR=#001080]target[/COLOR]) {
  [COLOR=#0000ff]char[/COLOR] *s;
  [COLOR=#0000ff]char[/COLOR] *t;
  [COLOR=#0000ff]char[/COLOR] *n;
  [COLOR=#0000ff]char[/COLOR] *a;
  [COLOR=#0000ff]char[/COLOR] *b;

  s = source;[COLOR=#008000]           // make a local copy of the source pointer[/COLOR]
  t = target;[COLOR=#008000]           // make a local copy of the target pointer[/COLOR]
  a = [COLOR=#795e26]strstr[/COLOR](s, [COLOR=#a31515]"//"[/COLOR]);[COLOR=#008000]  // test to see if the '//' token symbol is present in the source[/COLOR]
  [COLOR=#af00db]if[/COLOR] (a) {
    n = a;
    [COLOR=#795e26]strncpy[/COLOR](t, a + [COLOR=#098658]2[/COLOR], COMMENT_LENGTH);[COLOR=#008000]  // copy the comment contents out of the source string. Skip the comment symbol "%" or "//"[/COLOR]
    *(n) = [COLOR=#a31515]'[/COLOR][COLOR=#ee0000]\0[/COLOR][COLOR=#a31515]'[/COLOR];[COLOR=#008000]                        // overwrite the / symbol with a null (0) in the source string (*n points to the first elementof the token in the source string)[/COLOR]
    [COLOR=#af00db]return[/COLOR] (-[COLOR=#098658]1[/COLOR]);
  }
  a = [COLOR=#795e26]strstr[/COLOR](s, [COLOR=#a31515]"%"[/COLOR]);[COLOR=#008000]  // test to see if the '%' token symbol is present in the source[/COLOR]
  [COLOR=#af00db]if[/COLOR] (a) {
    n = a;[COLOR=#008000]                              // make a copy of the pointer to the comment symbol[/COLOR]
    [COLOR=#795e26]strncpy[/COLOR](t, a + [COLOR=#098658]1[/COLOR], COMMENT_LENGTH);[COLOR=#008000]  // copy the comment contents out of the source string. Skip the comment symbol "%" or "//"[/COLOR]
    *(n) = [COLOR=#a31515]'[/COLOR][COLOR=#ee0000]\0[/COLOR][COLOR=#a31515]'[/COLOR];[COLOR=#008000]                        // overwrite the % symbol with a null (0) in the source string (*n points to the first elementof the token in the source string)[/COLOR]
    [COLOR=#af00db]return[/COLOR] (-[COLOR=#098658]1[/COLOR]);
  }
  a = [COLOR=#795e26]strstr[/COLOR](s, [COLOR=#a31515]"("[/COLOR]);[COLOR=#008000]  // test to see if the '(' token symbol is present in the source[/COLOR]
  [COLOR=#af00db]if[/COLOR] (a) {
    b = [COLOR=#795e26]strstr[/COLOR](s, [COLOR=#a31515]")"[/COLOR]);[COLOR=#008000]  // test to see if ')' is present[/COLOR]
    [COLOR=#af00db]if[/COLOR] (b) {
      *(b) = [COLOR=#a31515]'[/COLOR][COLOR=#ee0000]\0[/COLOR][COLOR=#a31515]'[/COLOR];[COLOR=#008000]  // replace ')' with '\0' (null) to allow comment copy within (------)[/COLOR]
      [COLOR=#795e26]strncpy[/COLOR](t, a + [COLOR=#098658]1[/COLOR], COMMENT_LENGTH);
      *(a) = [COLOR=#a31515]'[/COLOR][COLOR=#ee0000]\0[/COLOR][COLOR=#a31515]'[/COLOR];[COLOR=#008000]  // replace '(' with '\0' (null) to truncate comment out of source string.[/COLOR]
      [COLOR=#af00db]return[/COLOR] (-[COLOR=#098658]1[/COLOR]);
    }
  }
  a = [COLOR=#795e26]strstr[/COLOR](s, [COLOR=#a31515]"{"[/COLOR]);[COLOR=#008000]  // test to see if the '{' token symbol is present in the source[/COLOR]
  [COLOR=#af00db]if[/COLOR] (a) {
    b = [COLOR=#795e26]strstr[/COLOR](s, [COLOR=#a31515]"}"[/COLOR]);[COLOR=#008000]  // test to see if '}' is present[/COLOR]
    [COLOR=#af00db]if[/COLOR] (b) {
      *(b) = [COLOR=#a31515]'[/COLOR][COLOR=#ee0000]\0[/COLOR][COLOR=#a31515]'[/COLOR];[COLOR=#008000]  // replace '}' with '\0' (null) to allow comment copy within {------}[/COLOR]
      [COLOR=#795e26]strncpy[/COLOR](t, a + [COLOR=#098658]1[/COLOR], COMMENT_LENGTH);
      *(a) = [COLOR=#a31515]'[/COLOR][COLOR=#ee0000]\0[/COLOR][COLOR=#a31515]'[/COLOR];[COLOR=#008000]  // replace '{' with '\0' (null) to truncate comment out of source string.[/COLOR]
      [COLOR=#af00db]return[/COLOR] (-[COLOR=#098658]1[/COLOR]);
    }
  }
  [COLOR=#af00db]return[/COLOR] ([COLOR=#098658]0[/COLOR]);
}
[COLOR=#008000]//------------------------------------------------------------------------------[/COLOR]
[COLOR=#008000]// A GCode block starts as a null terminated string and consists of a list of[/COLOR]
[COLOR=#008000]// letters (A..Z) as commands, with numeric value arguments associated with each letter.[/COLOR]
[COLOR=#008000]// As an example "X4.2".  Here the variable 'X' has a value of '4.2' in a decimal format.[/COLOR]
[COLOR=#008000]// This function copies a source string into target string and inserts null[/COLOR]
[COLOR=#008000]// terminators after each parameter (just befor the next alphabetic character).[/COLOR]
[COLOR=#008000]// Gcode parameters are now in the form of shorter strings "X10.0"  "M00"  "G01"  "Z34.9"[/COLOR]
[COLOR=#008000]// Each alphabetic value and associated argument value have a separator of 'null' terminating them.[/COLOR]
[COLOR=#008000]// Summary:[/COLOR]
[COLOR=#008000]// In "extract_gcode_commands()" the source GCode block is transformed into an array[/COLOR]
[COLOR=#008000]// of (sub)strings constructed from the original supplied string.[/COLOR]
[COLOR=#008000]// Because of the way the GC block is now formatted, parsing each block element is simplified[/COLOR]
[COLOR=#008000]// by examining the first character, then selecting the right command based on the alphabetic[/COLOR]
[COLOR=#008000]// character, incrementing the char pointer to point to the argument, then converting the argument value.[/COLOR]
[COLOR=#008000]// Most arrguments are in decimal format, however the G, M, T, F values are integers.[/COLOR]
[COLOR=#008000]//------------------------------------------------------------------------------[/COLOR]
[COLOR=#0000ff]int[/COLOR] [COLOR=#795e26]extract_gcode_commands[/COLOR]([COLOR=#267f99]T_gcparser[/COLOR] [COLOR=#0000ff]*[/COLOR][COLOR=#001080]gcp[/COLOR]) {
  [COLOR=#0000ff]int[/COLOR] f, i;
  [COLOR=#0000ff]char[/COLOR] *t;
  [COLOR=#0000ff]char[/COLOR] *s;
  s = [COLOR=#001080]gcp[/COLOR]->[COLOR=#001080]gc_codestrings[/COLOR];[COLOR=#008000]  // a block of gcode[/COLOR]
  t = [COLOR=#001080]gcp[/COLOR]->[COLOR=#001080]gc_codeparams[/COLOR];[COLOR=#008000]   // an array of strings, each a gcode command within the block[/COLOR]
  i = [COLOR=#098658]0[/COLOR];
  f = [COLOR=#098658]0[/COLOR];
  [COLOR=#af00db]while[/COLOR] (*s)[COLOR=#008000]  // start iterating through source string[/COLOR]
  {
    [COLOR=#af00db]if[/COLOR] ([COLOR=#795e26]isalpha[/COLOR](*s))[COLOR=#008000]       // if we find an alpha char[/COLOR]
    {[COLOR=#008000]                      // insert a null before it to terminate a preceeding field.[/COLOR]
      [COLOR=#af00db]if[/COLOR] (f) *t++ = [COLOR=#098658]0[/COLOR];[COLOR=#008000]     // (but only after the first time through...)[/COLOR]
      f = [COLOR=#098658]1[/COLOR];[COLOR=#008000]               // flip the first time flag...[/COLOR]
      [COLOR=#001080]gcp[/COLOR]->[COLOR=#001080]args[/COLOR][i++] = t;[COLOR=#008000]  // add each pointer in an array[] (pointers to strings)[/COLOR]
    }
    *t++ = [COLOR=#795e26]toupper[/COLOR](*s++);[COLOR=#008000]  // otherwise (by default) copy source char into dest; (also in uppercase).[/COLOR]
  }
  *(t) = [COLOR=#a31515]'[/COLOR][COLOR=#ee0000]\0[/COLOR][COLOR=#a31515]'[/COLOR];[COLOR=#008000]    // make sure to null terminate the last field.[/COLOR]
  [COLOR=#001080]gcp[/COLOR]->[COLOR=#001080]argc[/COLOR] = i;[COLOR=#008000]  // report the number of parameter fields in the block[/COLOR]
  [COLOR=#af00db]return[/COLOR] ([COLOR=#098658]0[/COLOR]);
}
[COLOR=#008000]//------------------------------------------------------------------------------[/COLOR]
[COLOR=#008000]// "strip_white_space"[/COLOR]
[COLOR=#008000]// Excludes controls chars or white space from source string, as it copies source to target.[/COLOR]
[COLOR=#008000]// Why? Because we need to have each command and its arguments running together with no gaps or separators.[/COLOR]
[COLOR=#008000]// e.g. 'X 1.2 G 01 M  6' becomes 'X1.2G01M6'[/COLOR]
[COLOR=#008000]//------------------------------------------------------------------------------[/COLOR]
[COLOR=#0000ff]void[/COLOR] [COLOR=#795e26]strip_white_space[/COLOR]([COLOR=#0000ff]char[/COLOR] [COLOR=#0000ff]*[/COLOR][COLOR=#001080]target_string[/COLOR], [COLOR=#0000ff]char[/COLOR] [COLOR=#0000ff]*[/COLOR][COLOR=#001080]source_string[/COLOR]) {
  [COLOR=#0000ff]char[/COLOR] *s;
  [COLOR=#0000ff]char[/COLOR] *t;
  s = source_string;
  t = target_string;
  [COLOR=#af00db]if[/COLOR] ([COLOR=#795e26]strlen[/COLOR](s) == [COLOR=#098658]0[/COLOR]) *t = [COLOR=#a31515]'[/COLOR][COLOR=#ee0000]\0[/COLOR][COLOR=#a31515]'[/COLOR];
  [COLOR=#af00db]while[/COLOR] (*s) {
    [COLOR=#af00db]while[/COLOR] ([COLOR=#795e26]isvalidchar[/COLOR](*s) == [COLOR=#098658]0[/COLOR]) s++;[COLOR=#008000]  // exclude spaces or other specific chars[/COLOR]
    *t++ = *s++;
  }
  *t = [COLOR=#a31515]'[/COLOR][COLOR=#ee0000]\0[/COLOR][COLOR=#a31515]'[/COLOR];
}
[COLOR=#008000]//------------------------------------------------------------------------------[/COLOR]
[COLOR=#0000ff]int[/COLOR] [COLOR=#795e26]isvalidchar[/COLOR]([COLOR=#0000ff]char[/COLOR] [COLOR=#001080]c[/COLOR])[COLOR=#008000]  // is the argument char in a list of valid chars?[/COLOR]
{
  [COLOR=#af00db]if[/COLOR] ([COLOR=#795e26]isspace[/COLOR](c)) [COLOR=#af00db]return[/COLOR] ([COLOR=#0000ff]false[/COLOR]);
  [COLOR=#af00db]else[/COLOR] [COLOR=#af00db]return[/COLOR] ([COLOR=#0000ff]true[/COLOR]);
}
[COLOR=#008000]//------------------------------------------------------------------------------[/COLOR]
[COLOR=#0000ff]void[/COLOR] [COLOR=#795e26]gc_strerror[/COLOR]() {
  [COLOR=#af00db]if[/COLOR] ([COLOR=#001080]gc_parser[/COLOR].[COLOR=#001080]gc_errors[/COLOR].[COLOR=#001080]missing_block[/COLOR]) { [COLOR=#795e26]snprintf[/COLOR]([COLOR=#001080]gc_parser[/COLOR].[COLOR=#001080]last_error_desc[/COLOR], ERROR_DESC_LENGTH, [COLOR=#a31515]"missing gc block on line [/COLOR][COLOR=#001080]%s[/COLOR][COLOR=#a31515]"[/COLOR], [COLOR=#001080]gc_parser[/COLOR].[COLOR=#001080]args[/COLOR][[COLOR=#098658]0[/COLOR]]); }
  [COLOR=#af00db]if[/COLOR] ([COLOR=#001080]gc_parser[/COLOR].[COLOR=#001080]gc_errors[/COLOR].[COLOR=#001080]block_too_long[/COLOR]) { [COLOR=#795e26]snprintf[/COLOR]([COLOR=#001080]gc_parser[/COLOR].[COLOR=#001080]last_error_desc[/COLOR], ERROR_DESC_LENGTH, [COLOR=#a31515]"block too long on line [/COLOR][COLOR=#001080]%s[/COLOR][COLOR=#a31515]"[/COLOR], [COLOR=#001080]gc_parser[/COLOR].[COLOR=#001080]args[/COLOR][[COLOR=#098658]0[/COLOR]]); }
  [COLOR=#af00db]if[/COLOR] ([COLOR=#001080]gc_parser[/COLOR].[COLOR=#001080]gc_errors[/COLOR].[COLOR=#001080]unknown_gc_token[/COLOR]) { [COLOR=#795e26]snprintf[/COLOR]([COLOR=#001080]gc_parser[/COLOR].[COLOR=#001080]last_error_desc[/COLOR], ERROR_DESC_LENGTH, [COLOR=#a31515]"unknown gc token on line [/COLOR][COLOR=#001080]%s[/COLOR][COLOR=#a31515]"[/COLOR], [COLOR=#001080]gc_parser[/COLOR].[COLOR=#001080]args[/COLOR][[COLOR=#098658]0[/COLOR]]); }
  [COLOR=#af00db]if[/COLOR] ([COLOR=#001080]gc_parser[/COLOR].[COLOR=#001080]gc_errors[/COLOR].[COLOR=#001080]bad_float_format[/COLOR]) { [COLOR=#795e26]snprintf[/COLOR]([COLOR=#001080]gc_parser[/COLOR].[COLOR=#001080]last_error_desc[/COLOR], ERROR_DESC_LENGTH, [COLOR=#a31515]"bad float format on line [/COLOR][COLOR=#001080]%s[/COLOR][COLOR=#a31515]"[/COLOR], [COLOR=#001080]gc_parser[/COLOR].[COLOR=#001080]args[/COLOR][[COLOR=#098658]0[/COLOR]]); }
  [COLOR=#af00db]if[/COLOR] ([COLOR=#001080]gc_parser[/COLOR].[COLOR=#001080]gc_errors[/COLOR].[COLOR=#001080]bad_integer_format[/COLOR]) { [COLOR=#795e26]snprintf[/COLOR]([COLOR=#001080]gc_parser[/COLOR].[COLOR=#001080]last_error_desc[/COLOR], ERROR_DESC_LENGTH, [COLOR=#a31515]"bad integer format on line [/COLOR][COLOR=#001080]%s[/COLOR][COLOR=#a31515]"[/COLOR], [COLOR=#001080]gc_parser[/COLOR].[COLOR=#001080]args[/COLOR][[COLOR=#098658]0[/COLOR]]); }
  [COLOR=#af00db]if[/COLOR] ([COLOR=#001080]gc_parser[/COLOR].[COLOR=#001080]gc_errors[/COLOR].[COLOR=#001080]too_many_arguments[/COLOR]) { [COLOR=#795e26]snprintf[/COLOR]([COLOR=#001080]gc_parser[/COLOR].[COLOR=#001080]last_error_desc[/COLOR], ERROR_DESC_LENGTH, [COLOR=#a31515]"too many arguments on line [/COLOR][COLOR=#001080]%s[/COLOR][COLOR=#a31515]"[/COLOR], [COLOR=#001080]gc_parser[/COLOR].[COLOR=#001080]args[/COLOR][[COLOR=#098658]0[/COLOR]]); }
  [COLOR=#af00db]if[/COLOR] ([COLOR=#001080]gc_parser[/COLOR].[COLOR=#001080]gc_errors[/COLOR].[COLOR=#001080]missing_comment_brace[/COLOR]) { [COLOR=#795e26]snprintf[/COLOR]([COLOR=#001080]gc_parser[/COLOR].[COLOR=#001080]last_error_desc[/COLOR], ERROR_DESC_LENGTH, [COLOR=#a31515]"missing comment brace on line [/COLOR][COLOR=#001080]%s[/COLOR][COLOR=#a31515]"[/COLOR], [COLOR=#001080]gc_parser[/COLOR].[COLOR=#001080]args[/COLOR][[COLOR=#098658]0[/COLOR]]); }
}
[COLOR=#008000]//------------------------------------------------------------------------------[/COLOR]
[COLOR=#008000]// converts string to a integer value with error detection.[/COLOR]
[COLOR=#008000]//------------------------------------------------------------------------------[/COLOR]
[COLOR=#0000ff]int[/COLOR] [COLOR=#795e26]safe_int[/COLOR]([COLOR=#0000ff]char[/COLOR] [COLOR=#0000ff]*[/COLOR][COLOR=#001080]c[/COLOR]) {
  [COLOR=#0000ff]char[/COLOR] *end;
  [COLOR=#0000ff]int[/COLOR] v = [COLOR=#098658]0[/COLOR];
  v = ([COLOR=#0000ff]int[/COLOR])[COLOR=#795e26]strtol[/COLOR](c, &end, [COLOR=#098658]10[/COLOR]);
  [COLOR=#af00db]if[/COLOR] (*end != [COLOR=#a31515]'[/COLOR][COLOR=#ee0000]\0[/COLOR][COLOR=#a31515]'[/COLOR] || errno != [COLOR=#098658]0[/COLOR]) {
    [COLOR=#001080]gc_parser[/COLOR].[COLOR=#001080]gc_errors[/COLOR].[COLOR=#001080]bad_integer_format[/COLOR] = [COLOR=#098658]1[/COLOR];
    [COLOR=#795e26]gc_strerror[/COLOR]();[COLOR=#008000]  // convert error to string[/COLOR]
    errno = [COLOR=#098658]0[/COLOR];
  }
  [COLOR=#af00db]return[/COLOR] (v);
}
[COLOR=#008000]//------------------------------------------------------------------------------[/COLOR]
[COLOR=#008000]// converts string to a float value with error detection.[/COLOR]
[COLOR=#008000]//------------------------------------------------------------------------------[/COLOR]
[COLOR=#0000ff]float[/COLOR] [COLOR=#795e26]safe_float[/COLOR]([COLOR=#0000ff]char[/COLOR] [COLOR=#0000ff]*[/COLOR][COLOR=#001080]c[/COLOR]) {
  [COLOR=#0000ff]char[/COLOR] *end;
  [COLOR=#0000ff]float[/COLOR] f;
  f = ([COLOR=#0000ff]float[/COLOR])[COLOR=#795e26]strtod[/COLOR](c, &end);
  [COLOR=#af00db]if[/COLOR] (*end != [COLOR=#a31515]'[/COLOR][COLOR=#ee0000]\0[/COLOR][COLOR=#a31515]'[/COLOR] || errno != [COLOR=#098658]0[/COLOR]) {
    [COLOR=#001080]gc_parser[/COLOR].[COLOR=#001080]gc_errors[/COLOR].[COLOR=#001080]bad_float_format[/COLOR] = [COLOR=#098658]1[/COLOR];
    [COLOR=#795e26]gc_strerror[/COLOR]();[COLOR=#008000]  // convert gcode error to string.[/COLOR]
    errno = [COLOR=#098658]0[/COLOR];
  }
  [COLOR=#af00db]return[/COLOR] (f);
}
[COLOR=#008000]//------------------------------------------------------------------------------[/COLOR]
[COLOR=#008000]// Tests to see if there are characters in the string that would support a float format.[/COLOR]
[COLOR=#008000]//------------------------------------------------------------------------------[/COLOR]
[COLOR=#0000ff]int[/COLOR] [COLOR=#795e26]isfloatstr[/COLOR]([COLOR=#0000ff]char[/COLOR] [COLOR=#0000ff]*[/COLOR][COLOR=#001080]s[/COLOR]) {
  [COLOR=#0000ff]register[/COLOR] [COLOR=#0000ff]char[/COLOR] *c;
  c = s;
  [COLOR=#af00db]while[/COLOR] (*c) {
    [COLOR=#af00db]if[/COLOR] (([COLOR=#795e26]isdigit[/COLOR](*c)) || (*c == [COLOR=#a31515]'.'[/COLOR]) || (*c == [COLOR=#a31515]'+'[/COLOR]) || (*c == [COLOR=#a31515]'-'[/COLOR]) || (*c == [COLOR=#a31515]' '[/COLOR]) || (*c == [COLOR=#a31515]'E'[/COLOR]) || (*c == [COLOR=#a31515]'e'[/COLOR])) c++;
    [COLOR=#af00db]else[/COLOR] [COLOR=#af00db]return[/COLOR] ([COLOR=#0000ff]false[/COLOR]);
  }
  [COLOR=#af00db]return[/COLOR] ([COLOR=#0000ff]true[/COLOR]);
}
[COLOR=#008000]//------------------------------------------------------------------------------[/COLOR]
[COLOR=#0000ff]void[/COLOR] [COLOR=#795e26]event_queue_init[/COLOR]([COLOR=#0000ff]void[/COLOR]) {
  [COLOR=#0000ff]int[/COLOR] i;
  [COLOR=#001080]event_queue[/COLOR].[COLOR=#001080]state[/COLOR].[COLOR=#001080]busy[/COLOR] = [COLOR=#098658]0[/COLOR];
  [COLOR=#001080]event_queue[/COLOR].[COLOR=#001080]state[/COLOR].[COLOR=#001080]paused[/COLOR] = [COLOR=#098658]0[/COLOR];
  [COLOR=#001080]event_queue[/COLOR].[COLOR=#001080]state[/COLOR].[COLOR=#001080]fault[/COLOR] = [COLOR=#098658]0[/COLOR];
  [COLOR=#001080]event_queue[/COLOR].[COLOR=#001080]state[/COLOR].[COLOR=#001080]full[/COLOR] = [COLOR=#098658]0[/COLOR];
  [COLOR=#001080]event_queue[/COLOR].[COLOR=#001080]head[/COLOR] = [COLOR=#098658]0[/COLOR];
  [COLOR=#001080]event_queue[/COLOR].[COLOR=#001080]tail[/COLOR] = [COLOR=#098658]0[/COLOR];
  [COLOR=#001080]event_queue[/COLOR].[COLOR=#001080]total[/COLOR] = [COLOR=#098658]0[/COLOR];
  [COLOR=#001080]event_queue[/COLOR].[COLOR=#001080]function_mode[/COLOR] = fm_null;
  [COLOR=#001080]event_queue[/COLOR].[COLOR=#001080]count[/COLOR] = &get_event_count;
  [COLOR=#001080]event_queue[/COLOR].[COLOR=#001080]add[/COLOR] = &add_event;
  [COLOR=#001080]event_queue[/COLOR].[COLOR=#001080]next[/COLOR] = &get_next;
  [COLOR=#af00db]for[/COLOR] (i = [COLOR=#098658]0[/COLOR]; i < MAX_EVENT_QUEUE; i++) {
    [COLOR=#795e26]clear_event[/COLOR](&[COLOR=#001080]event_queue[/COLOR].[COLOR=#001080]events[/COLOR][i]);
  }
}
[COLOR=#008000]//------------------------------------------------------------------------------[/COLOR]
[COLOR=#0000ff]void[/COLOR] [COLOR=#795e26]clear_event[/COLOR]([COLOR=#267f99]T_event[/COLOR] [COLOR=#0000ff]*[/COLOR][COLOR=#001080]evt[/COLOR]) {
  [COLOR=#0000ff]int[/COLOR] k;
  [COLOR=#001080]evt[/COLOR]->[COLOR=#001080]line_number[/COLOR] = -[COLOR=#098658]1[/COLOR];
  [COLOR=#001080]evt[/COLOR]->[COLOR=#001080]gcode_param[/COLOR][[COLOR=#098658]0[/COLOR]] = -[COLOR=#098658]1[/COLOR];
  [COLOR=#001080]evt[/COLOR]->[COLOR=#001080]gcode_param[/COLOR][[COLOR=#098658]1[/COLOR]] = -[COLOR=#098658]1[/COLOR];
  [COLOR=#001080]evt[/COLOR]->[COLOR=#001080]gcode_param[/COLOR][[COLOR=#098658]2[/COLOR]] = -[COLOR=#098658]1[/COLOR];
  [COLOR=#001080]evt[/COLOR]->[COLOR=#001080]gcode_param[/COLOR][[COLOR=#098658]3[/COLOR]] = -[COLOR=#098658]1[/COLOR];
  [COLOR=#001080]evt[/COLOR]->[COLOR=#001080]mcode_param[/COLOR][[COLOR=#098658]0[/COLOR]] = -[COLOR=#098658]1[/COLOR];
  [COLOR=#001080]evt[/COLOR]->[COLOR=#001080]mcode_param[/COLOR][[COLOR=#098658]1[/COLOR]] = -[COLOR=#098658]1[/COLOR];
  [COLOR=#001080]evt[/COLOR]->[COLOR=#001080]mcode_param[/COLOR][[COLOR=#098658]2[/COLOR]] = -[COLOR=#098658]1[/COLOR];
  [COLOR=#001080]evt[/COLOR]->[COLOR=#001080]mcode_param[/COLOR][[COLOR=#098658]3[/COLOR]] = -[COLOR=#098658]1[/COLOR];
  [COLOR=#001080]evt[/COLOR]->[COLOR=#001080]coord_index[/COLOR] = -[COLOR=#098658]1[/COLOR];
  [COLOR=#001080]evt[/COLOR]->[COLOR=#001080]dwell_time[/COLOR] = [COLOR=#098658]0[/COLOR];
  [COLOR=#001080]evt[/COLOR]->[COLOR=#001080]feed_rate[/COLOR] = [COLOR=#098658]0.0[/COLOR];
  [COLOR=#001080]evt[/COLOR]->[COLOR=#001080]speed[/COLOR] = [COLOR=#098658]0.0[/COLOR];
  [COLOR=#001080]evt[/COLOR]->[COLOR=#001080]op_mode[/COLOR] = -[COLOR=#098658]1[/COLOR];
  [COLOR=#001080]evt[/COLOR]->[COLOR=#001080]tool_select[/COLOR] = -[COLOR=#098658]1[/COLOR];
  [COLOR=#001080]evt[/COLOR]->[COLOR=#001080]field_flags[/COLOR].[COLOR=#001080]bits[/COLOR] = [COLOR=#098658]0[/COLOR];[COLOR=#008000]  // clear all the bits asociated with fields passed in a gcode block[/COLOR]
  [COLOR=#af00db]for[/COLOR] (k = [COLOR=#098658]0[/COLOR]; k < MAX_EVENT_PARAMS; k++) {
    [COLOR=#001080]evt[/COLOR]->[COLOR=#001080]xyz[/COLOR][k] = [COLOR=#098658]0.0[/COLOR];
    [COLOR=#001080]evt[/COLOR]->[COLOR=#001080]abc[/COLOR][k] = [COLOR=#098658]0.0[/COLOR];
    [COLOR=#001080]evt[/COLOR]->[COLOR=#001080]uvw[/COLOR][k] = [COLOR=#098658]0.0[/COLOR];
  }
}
[COLOR=#008000]//------------------------------------------------------------------------------[/COLOR]
[COLOR=#008000]// *get_next(); method returns a pointer to the next available 'T_event' in 'event_queue.events[]' buffer.[/COLOR]
[COLOR=#008000]// At reset, tail = 0 is used to return the first 'next'.[/COLOR]
[COLOR=#008000]// After incrementing the tail pointer we wrap the array boundary by anding it with (MAX_EVENT_QUEUE-1).[/COLOR]
[COLOR=#008000]// MAX_EVENT_QUEUE must be a power of 2 for this to work. 8,16,32,64,128 etc.[/COLOR]
[COLOR=#008000]// Note: currently it's 64 (1/06/2022)[/COLOR]
[COLOR=#008000]// Syntax: newevent = event_queue.next();[/COLOR]
[COLOR=#008000]// Side Effect: Resets the 'full' flag of the event queue if the event count is below a lower threshold.[/COLOR]
[COLOR=#008000]// i.e. the buffer WILL accept new events.[/COLOR]
[COLOR=#008000]//------------------------------------------------------------------------------[/COLOR]
[COLOR=#267f99]T_event[/COLOR] [COLOR=#0000ff]*[/COLOR][COLOR=#795e26]get_next[/COLOR]([COLOR=#0000ff]void[/COLOR]) {
  T_event *p;
  [COLOR=#af00db]if[/COLOR] ([COLOR=#001080]event_queue[/COLOR].[COLOR=#795e26]count[/COLOR]() > [COLOR=#098658]0[/COLOR]) {
    p = &[COLOR=#001080]event_queue[/COLOR].[COLOR=#001080]events[/COLOR][[COLOR=#001080]event_queue[/COLOR].[COLOR=#001080]tail[/COLOR]];
    [COLOR=#001080]event_queue[/COLOR].[COLOR=#001080]tail[/COLOR]++;
    [COLOR=#001080]event_queue[/COLOR].[COLOR=#001080]tail[/COLOR] &= (MAX_EVENT_QUEUE - [COLOR=#098658]1[/COLOR]);
    [COLOR=#af00db]if[/COLOR] ([COLOR=#001080]event_queue[/COLOR].[COLOR=#795e26]count[/COLOR]() < LOWER_EVENT_BUFFER_THRESHOLD) [COLOR=#001080]event_queue[/COLOR].[COLOR=#001080]state[/COLOR].[COLOR=#001080]full[/COLOR] = [COLOR=#098658]0[/COLOR];
  } [COLOR=#af00db]else[/COLOR] p = [COLOR=#0000ff]NULL[/COLOR];
  [COLOR=#af00db]return[/COLOR] (p);
}
[COLOR=#008000]//------------------------------------------------------------------------------[/COLOR]
[COLOR=#0000ff]void[/COLOR] [COLOR=#795e26]copy_event_to_machine[/COLOR]([COLOR=#267f99]T_event[/COLOR] [COLOR=#0000ff]*[/COLOR][COLOR=#001080]evt[/COLOR]) {
}
[COLOR=#008000]//------------------------------------------------------------------------------[/COLOR]
[COLOR=#0000ff]void[/COLOR] [COLOR=#795e26]copy_next_event_to_machine[/COLOR]([COLOR=#0000ff]void[/COLOR]) {
  T_event *e;
  [COLOR=#af00db]if[/COLOR] (([COLOR=#001080]event_queue[/COLOR].[COLOR=#001080]state[/COLOR].[COLOR=#001080]paused[/COLOR] == [COLOR=#098658]0[/COLOR]) && ([COLOR=#001080]event_queue[/COLOR].[COLOR=#001080]state[/COLOR].[COLOR=#001080]busy[/COLOR] == [COLOR=#098658]0[/COLOR]) && ([COLOR=#001080]event_queue[/COLOR].[COLOR=#001080]state[/COLOR].[COLOR=#001080]fault[/COLOR] == [COLOR=#098658]0[/COLOR]))[COLOR=#008000]  // copy the next event to the machine if 'paused' is false[/COLOR]
  {
    e = [COLOR=#001080]event_queue[/COLOR].[COLOR=#795e26]next[/COLOR]();[COLOR=#008000]  // if next() is skipped, the buffer keeps the last event in the queue[/COLOR]
    [COLOR=#af00db]if[/COLOR] (e != [COLOR=#0000ff]NULL[/COLOR])[COLOR=#008000]           // if there is an event in the queue, event 'e' will not be NULL[/COLOR]
    {
      [COLOR=#af00db]if[/COLOR] ([COLOR=#001080]e[/COLOR]->[COLOR=#001080]field_flags[/COLOR].[COLOR=#001080]x_changed[/COLOR]) [COLOR=#001080]machine[/COLOR].[COLOR=#001080]xyz_position[/COLOR][[COLOR=#098658]0[/COLOR]] = [COLOR=#001080]e[/COLOR]->[COLOR=#001080]xyz[/COLOR][[COLOR=#098658]0[/COLOR]];[COLOR=#008000]  // only update the values that have changed or are modal.[/COLOR]
      [COLOR=#af00db]if[/COLOR] ([COLOR=#001080]e[/COLOR]->[COLOR=#001080]field_flags[/COLOR].[COLOR=#001080]y_changed[/COLOR]) [COLOR=#001080]machine[/COLOR].[COLOR=#001080]xyz_position[/COLOR][[COLOR=#098658]1[/COLOR]] = [COLOR=#001080]e[/COLOR]->[COLOR=#001080]xyz[/COLOR][[COLOR=#098658]1[/COLOR]];
      [COLOR=#af00db]if[/COLOR] ([COLOR=#001080]e[/COLOR]->[COLOR=#001080]field_flags[/COLOR].[COLOR=#001080]z_changed[/COLOR]) [COLOR=#001080]machine[/COLOR].[COLOR=#001080]xyz_position[/COLOR][[COLOR=#098658]2[/COLOR]] = [COLOR=#001080]e[/COLOR]->[COLOR=#001080]xyz[/COLOR][[COLOR=#098658]2[/COLOR]];
      [COLOR=#001080]machine[/COLOR].[COLOR=#001080]state[/COLOR].[COLOR=#001080]changed[/COLOR] = [COLOR=#098658]1[/COLOR];
    }
  }
}
[COLOR=#008000]//------------------------------------------------------------------------------[/COLOR]
[COLOR=#008000]// pushes a T_event onto the event_queue circular buffer.[/COLOR]
[COLOR=#008000]// no returned value.[/COLOR]
[COLOR=#008000]// Intially the head pointer will be 0.[/COLOR]
[COLOR=#008000]// The first push will be to event_queue.events[0].[/COLOR]
[COLOR=#008000]// After setting up the event content at [0], the head pointer is incremented to 1 ready for the[/COLOR]
[COLOR=#008000]// next store operation.[/COLOR]
[COLOR=#008000]// The head pointer wraps around the array boundary by anding with (MAX_EVENT_QUEUE-1).[/COLOR]
[COLOR=#008000]// MAX_EVENT_QUEUE must be a power of 2 for this to work. 8,16,32,64,128 etc.[/COLOR]
[COLOR=#008000]// syntax: event_queue.add(T_event *new_event);[/COLOR]
[COLOR=#008000]// side effect: Sets the 'full' flag of the event queue if the event_queue.count() is above an upper threshold.[/COLOR]
[COLOR=#008000]// i.e. the buffer will NOT accept new events.[/COLOR]
[COLOR=#008000]//------------------------------------------------------------------------------[/COLOR]
[COLOR=#0000ff]void[/COLOR] [COLOR=#795e26]add_event[/COLOR]([COLOR=#267f99]T_event[/COLOR] [COLOR=#0000ff]*[/COLOR][COLOR=#001080]evt[/COLOR]) {
  [COLOR=#0000ff]int[/COLOR] i;
  [COLOR=#001080]event_queue[/COLOR].[COLOR=#001080]events[/COLOR][[COLOR=#001080]event_queue[/COLOR].[COLOR=#001080]head[/COLOR]].[COLOR=#001080]field_flags[/COLOR].[COLOR=#001080]bits[/COLOR] = [COLOR=#001080]evt[/COLOR]->[COLOR=#001080]field_flags[/COLOR].[COLOR=#001080]bits[/COLOR];
  [COLOR=#001080]event_queue[/COLOR].[COLOR=#001080]events[/COLOR][[COLOR=#001080]event_queue[/COLOR].[COLOR=#001080]head[/COLOR]].[COLOR=#001080]line_number[/COLOR] = [COLOR=#001080]evt[/COLOR]->[COLOR=#001080]line_number[/COLOR];
  [COLOR=#001080]event_queue[/COLOR].[COLOR=#001080]events[/COLOR][[COLOR=#001080]event_queue[/COLOR].[COLOR=#001080]head[/COLOR]].[COLOR=#001080]gcode_param[/COLOR][[COLOR=#098658]0[/COLOR]] = [COLOR=#001080]evt[/COLOR]->[COLOR=#001080]gcode_param[/COLOR][[COLOR=#098658]0[/COLOR]];
  [COLOR=#001080]event_queue[/COLOR].[COLOR=#001080]events[/COLOR][[COLOR=#001080]event_queue[/COLOR].[COLOR=#001080]head[/COLOR]].[COLOR=#001080]gcode_param[/COLOR][[COLOR=#098658]1[/COLOR]] = [COLOR=#001080]evt[/COLOR]->[COLOR=#001080]gcode_param[/COLOR][[COLOR=#098658]1[/COLOR]];
  [COLOR=#001080]event_queue[/COLOR].[COLOR=#001080]events[/COLOR][[COLOR=#001080]event_queue[/COLOR].[COLOR=#001080]head[/COLOR]].[COLOR=#001080]gcode_param[/COLOR][[COLOR=#098658]2[/COLOR]] = [COLOR=#001080]evt[/COLOR]->[COLOR=#001080]gcode_param[/COLOR][[COLOR=#098658]2[/COLOR]];
  [COLOR=#001080]event_queue[/COLOR].[COLOR=#001080]events[/COLOR][[COLOR=#001080]event_queue[/COLOR].[COLOR=#001080]head[/COLOR]].[COLOR=#001080]gcode_param[/COLOR][[COLOR=#098658]3[/COLOR]] = [COLOR=#001080]evt[/COLOR]->[COLOR=#001080]gcode_param[/COLOR][[COLOR=#098658]3[/COLOR]];
  [COLOR=#001080]event_queue[/COLOR].[COLOR=#001080]events[/COLOR][[COLOR=#001080]event_queue[/COLOR].[COLOR=#001080]head[/COLOR]].[COLOR=#001080]mcode_param[/COLOR][[COLOR=#098658]0[/COLOR]] = [COLOR=#001080]evt[/COLOR]->[COLOR=#001080]mcode_param[/COLOR][[COLOR=#098658]0[/COLOR]];
  [COLOR=#001080]event_queue[/COLOR].[COLOR=#001080]events[/COLOR][[COLOR=#001080]event_queue[/COLOR].[COLOR=#001080]head[/COLOR]].[COLOR=#001080]mcode_param[/COLOR][[COLOR=#098658]1[/COLOR]] = [COLOR=#001080]evt[/COLOR]->[COLOR=#001080]mcode_param[/COLOR][[COLOR=#098658]1[/COLOR]];
  [COLOR=#001080]event_queue[/COLOR].[COLOR=#001080]events[/COLOR][[COLOR=#001080]event_queue[/COLOR].[COLOR=#001080]head[/COLOR]].[COLOR=#001080]mcode_param[/COLOR][[COLOR=#098658]2[/COLOR]] = [COLOR=#001080]evt[/COLOR]->[COLOR=#001080]mcode_param[/COLOR][[COLOR=#098658]2[/COLOR]];
  [COLOR=#001080]event_queue[/COLOR].[COLOR=#001080]events[/COLOR][[COLOR=#001080]event_queue[/COLOR].[COLOR=#001080]head[/COLOR]].[COLOR=#001080]mcode_param[/COLOR][[COLOR=#098658]3[/COLOR]] = [COLOR=#001080]evt[/COLOR]->[COLOR=#001080]mcode_param[/COLOR][[COLOR=#098658]3[/COLOR]];
  [COLOR=#001080]event_queue[/COLOR].[COLOR=#001080]events[/COLOR][[COLOR=#001080]event_queue[/COLOR].[COLOR=#001080]head[/COLOR]].[COLOR=#001080]tool_select[/COLOR] = [COLOR=#001080]evt[/COLOR]->[COLOR=#001080]tool_select[/COLOR];
  [COLOR=#001080]event_queue[/COLOR].[COLOR=#001080]events[/COLOR][[COLOR=#001080]event_queue[/COLOR].[COLOR=#001080]head[/COLOR]].[COLOR=#001080]feed_rate[/COLOR] = [COLOR=#001080]evt[/COLOR]->[COLOR=#001080]feed_rate[/COLOR];
  [COLOR=#001080]event_queue[/COLOR].[COLOR=#001080]events[/COLOR][[COLOR=#001080]event_queue[/COLOR].[COLOR=#001080]head[/COLOR]].[COLOR=#001080]speed[/COLOR] = [COLOR=#001080]evt[/COLOR]->[COLOR=#001080]speed[/COLOR];
  [COLOR=#001080]event_queue[/COLOR].[COLOR=#001080]events[/COLOR][[COLOR=#001080]event_queue[/COLOR].[COLOR=#001080]head[/COLOR]].[COLOR=#001080]radius[/COLOR] = [COLOR=#001080]evt[/COLOR]->[COLOR=#001080]radius[/COLOR];
  [COLOR=#001080]event_queue[/COLOR].[COLOR=#001080]events[/COLOR][[COLOR=#001080]event_queue[/COLOR].[COLOR=#001080]head[/COLOR]].[COLOR=#001080]dwell_time[/COLOR] = [COLOR=#001080]evt[/COLOR]->[COLOR=#001080]dwell_time[/COLOR];
  [COLOR=#001080]event_queue[/COLOR].[COLOR=#001080]events[/COLOR][[COLOR=#001080]event_queue[/COLOR].[COLOR=#001080]head[/COLOR]].[COLOR=#001080]coord_index[/COLOR] = [COLOR=#001080]evt[/COLOR]->[COLOR=#001080]coord_index[/COLOR];
  [COLOR=#af00db]for[/COLOR] (i = [COLOR=#098658]0[/COLOR]; i < MAX_EVENT_PARAMS; i++) {
    [COLOR=#001080]event_queue[/COLOR].[COLOR=#001080]events[/COLOR][[COLOR=#001080]event_queue[/COLOR].[COLOR=#001080]head[/COLOR]].[COLOR=#001080]xyz[/COLOR][i] = [COLOR=#001080]evt[/COLOR]->[COLOR=#001080]xyz[/COLOR][i];
    [COLOR=#001080]event_queue[/COLOR].[COLOR=#001080]events[/COLOR][[COLOR=#001080]event_queue[/COLOR].[COLOR=#001080]head[/COLOR]].[COLOR=#001080]abc[/COLOR][i] = [COLOR=#001080]evt[/COLOR]->[COLOR=#001080]abc[/COLOR][i];
    [COLOR=#001080]event_queue[/COLOR].[COLOR=#001080]events[/COLOR][[COLOR=#001080]event_queue[/COLOR].[COLOR=#001080]head[/COLOR]].[COLOR=#001080]uvw[/COLOR][i] = [COLOR=#001080]evt[/COLOR]->[COLOR=#001080]uvw[/COLOR][i];
  }
  [COLOR=#001080]event_queue[/COLOR].[COLOR=#001080]head[/COLOR]++;
  [COLOR=#001080]event_queue[/COLOR].[COLOR=#001080]head[/COLOR] &= (MAX_EVENT_QUEUE - [COLOR=#098658]1[/COLOR]);
  [COLOR=#af00db]if[/COLOR] ([COLOR=#001080]event_queue[/COLOR].[COLOR=#795e26]count[/COLOR]() > UPPER_EVENT_BUFFER_THRESHOLD) [COLOR=#001080]event_queue[/COLOR].[COLOR=#001080]state[/COLOR].[COLOR=#001080]full[/COLOR] = [COLOR=#098658]1[/COLOR];
}
[COLOR=#008000]//------------------------------------------------------------------------------[/COLOR]
[COLOR=#008000]// get_event_count calculates the number of events in the circular queue buffer.[/COLOR]
[COLOR=#008000]// side effects: none[/COLOR]
[COLOR=#008000]// syntax:  some_value = event_queue.count();[/COLOR]
[COLOR=#008000]//------------------------------------------------------------------------------[/COLOR]
[COLOR=#0000ff]int[/COLOR] [COLOR=#795e26]get_event_count[/COLOR]([COLOR=#0000ff]void[/COLOR]) {
  [COLOR=#0000ff]unsigned[/COLOR] [COLOR=#0000ff]int[/COLOR] event_count;
  [COLOR=#af00db]if[/COLOR] ([COLOR=#001080]event_queue[/COLOR].[COLOR=#001080]head[/COLOR] >= [COLOR=#001080]event_queue[/COLOR].[COLOR=#001080]tail[/COLOR]) event_count = [COLOR=#001080]event_queue[/COLOR].[COLOR=#001080]head[/COLOR] - [COLOR=#001080]event_queue[/COLOR].[COLOR=#001080]tail[/COLOR];
  [COLOR=#af00db]else[/COLOR] event_count = (MAX_EVENT_QUEUE - [COLOR=#001080]event_queue[/COLOR].[COLOR=#001080]tail[/COLOR]) + [COLOR=#001080]event_queue[/COLOR].[COLOR=#001080]head[/COLOR];
  [COLOR=#af00db]return[/COLOR] (event_count);
}
[COLOR=#008000]//------------------------------------------------------------------------------[/COLOR]
[COLOR=#008000]//[/COLOR]
[COLOR=#008000]//------------------------------------------------------------------------------[/COLOR]
[COLOR=#0000ff]void[/COLOR] [COLOR=#795e26]machine_init[/COLOR]([COLOR=#0000ff]void[/COLOR]) {
  [COLOR=#0000ff]int[/COLOR] i;
  [COLOR=#001080]machine[/COLOR].[COLOR=#001080]state[/COLOR].[COLOR=#001080]changed[/COLOR] = [COLOR=#098658]0[/COLOR];
  [COLOR=#001080]machine[/COLOR].[COLOR=#001080]state[/COLOR].[COLOR=#001080]enabled[/COLOR] = [COLOR=#098658]0[/COLOR];
  [COLOR=#af00db]for[/COLOR] (i = [COLOR=#098658]0[/COLOR]; i < N_AXES; i++) {
    [COLOR=#795e26]sprintf[/COLOR]([COLOR=#001080]machine[/COLOR].[COLOR=#001080]axes[/COLOR][i].[COLOR=#001080]name[/COLOR], [COLOR=#a31515]"axis#[/COLOR][COLOR=#001080]%d[/COLOR][COLOR=#a31515]"[/COLOR], i);
    [COLOR=#001080]machine[/COLOR].[COLOR=#001080]axes[/COLOR][i].[COLOR=#001080]axis_cal[/COLOR].[COLOR=#001080]offset_comp[/COLOR] = [COLOR=#098658]0.0[/COLOR];
    [COLOR=#001080]machine[/COLOR].[COLOR=#001080]axes[/COLOR][i].[COLOR=#001080]axis_cal[/COLOR].[COLOR=#001080]scale_comp[/COLOR] = [COLOR=#098658]1.0[/COLOR];
    [COLOR=#001080]machine[/COLOR].[COLOR=#001080]axes[/COLOR][i].[COLOR=#001080]axis_cal[/COLOR].[COLOR=#001080]gear_ratio[/COLOR] = DEFAULT_GEAR_RATIO;
    [COLOR=#001080]machine[/COLOR].[COLOR=#001080]axes[/COLOR][i].[COLOR=#001080]axis_cal[/COLOR].[COLOR=#001080]leadscrew_pitch[/COLOR] = DEFAULT_LEAD_SCREW_PITCH;
    [COLOR=#001080]machine[/COLOR].[COLOR=#001080]axes[/COLOR][i].[COLOR=#001080]axis_cal[/COLOR].[COLOR=#001080]steps_rev[/COLOR] = DEFAULT_STEPS_REV;
    [COLOR=#001080]machine[/COLOR].[COLOR=#001080]axes[/COLOR][i].[COLOR=#001080]axis_class[/COLOR] = DEFAULT_AXIS_CLASS;
    [COLOR=#001080]machine[/COLOR].[COLOR=#001080]axes[/COLOR][i].[COLOR=#001080]axis_cal[/COLOR].[COLOR=#001080]distance_perstep[/COLOR] = [COLOR=#098658]0.0[/COLOR];
    [COLOR=#001080]machine[/COLOR].[COLOR=#001080]axes[/COLOR][i].[COLOR=#001080]acceleration_factor[/COLOR] = [COLOR=#098658]1.0[/COLOR];
  }

  [COLOR=#af00db]for[/COLOR] (i = [COLOR=#098658]0[/COLOR]; i < N_AXES; i++) {
[COLOR=#008000]    // machine.ramp_envelope.lower_threshold[i]  = 0.0;   // each axis has an associated ramp calculation structure[/COLOR]
[COLOR=#008000]    // machine.ramp_envelope.upper_threshold[i]  = 0.0;[/COLOR]
[COLOR=#008000]    // machine.ramp_envelope.ramp_distance[i]    = 0.0;[/COLOR]
[COLOR=#008000]    // machine.ramp_envelope.ramp_gradient[i]    = 0.0;[/COLOR]
[COLOR=#008000]    // machine.ramp_envelope.ramp_steps[i]       = 0.0;[/COLOR]
  }

  [COLOR=#af00db]for[/COLOR] (i = [COLOR=#098658]0[/COLOR]; i < N_TOOLS; i++)[COLOR=#008000]  // initialize multiple tools[/COLOR]
  {
    [COLOR=#795e26]sprintf[/COLOR]([COLOR=#001080]machine[/COLOR].[COLOR=#001080]tools[/COLOR][i].[COLOR=#001080]name[/COLOR], [COLOR=#a31515]"tool#[/COLOR][COLOR=#001080]%d[/COLOR][COLOR=#a31515]"[/COLOR], i);
    [COLOR=#001080]machine[/COLOR].[COLOR=#001080]tools[/COLOR][i].[COLOR=#001080]params[/COLOR].[COLOR=#001080]xyz_comp[/COLOR][[COLOR=#098658]0[/COLOR]] = [COLOR=#098658]0.0[/COLOR];
    [COLOR=#001080]machine[/COLOR].[COLOR=#001080]tools[/COLOR][i].[COLOR=#001080]params[/COLOR].[COLOR=#001080]xyz_comp[/COLOR][[COLOR=#098658]1[/COLOR]] = [COLOR=#098658]0.0[/COLOR];
    [COLOR=#001080]machine[/COLOR].[COLOR=#001080]tools[/COLOR][i].[COLOR=#001080]params[/COLOR].[COLOR=#001080]xyz_comp[/COLOR][[COLOR=#098658]2[/COLOR]] = [COLOR=#098658]0.0[/COLOR];
    [COLOR=#001080]machine[/COLOR].[COLOR=#001080]tools[/COLOR][i].[COLOR=#001080]params[/COLOR].[COLOR=#001080]xyz_offset[/COLOR][[COLOR=#098658]0[/COLOR]] = [COLOR=#098658]0.0[/COLOR];
    [COLOR=#001080]machine[/COLOR].[COLOR=#001080]tools[/COLOR][i].[COLOR=#001080]params[/COLOR].[COLOR=#001080]xyz_offset[/COLOR][[COLOR=#098658]1[/COLOR]] = [COLOR=#098658]0.0[/COLOR];
    [COLOR=#001080]machine[/COLOR].[COLOR=#001080]tools[/COLOR][i].[COLOR=#001080]params[/COLOR].[COLOR=#001080]xyz_offset[/COLOR][[COLOR=#098658]2[/COLOR]] = [COLOR=#098658]0.0[/COLOR];
    [COLOR=#001080]machine[/COLOR].[COLOR=#001080]tools[/COLOR][i].[COLOR=#001080]params[/COLOR].[COLOR=#001080]radius[/COLOR] = [COLOR=#098658]0.0[/COLOR];
    [COLOR=#001080]machine[/COLOR].[COLOR=#001080]tools[/COLOR][i].[COLOR=#001080]params[/COLOR].[COLOR=#001080]height[/COLOR] = [COLOR=#098658]0.0[/COLOR];
  }
[COLOR=#008000]  // initialize multiple origins.[/COLOR]
[COLOR=#008000]  // These are 'offsets' relative to the absolute coordinates of each set of axes[/COLOR]
[COLOR=#008000]  // They will give relative coordinates in each case.[/COLOR]
  [COLOR=#af00db]for[/COLOR] (i = [COLOR=#098658]0[/COLOR]; i < N_ORIGINS; i++)[COLOR=#008000]  // initialize multiple origins. thse are offsets relative to the absolute coordinates[/COLOR]
  {
    [COLOR=#795e26]sprintf[/COLOR]([COLOR=#001080]machine[/COLOR].[COLOR=#001080]origins[/COLOR][i].[COLOR=#001080]name[/COLOR], [COLOR=#a31515]"org#[/COLOR][COLOR=#001080]%d[/COLOR][COLOR=#a31515]"[/COLOR], i);
    [COLOR=#001080]machine[/COLOR].[COLOR=#001080]origins[/COLOR][i].[COLOR=#001080]pt[/COLOR][[COLOR=#098658]0[/COLOR]] = [COLOR=#098658]0.0[/COLOR];
    [COLOR=#001080]machine[/COLOR].[COLOR=#001080]origins[/COLOR][i].[COLOR=#001080]pt[/COLOR][[COLOR=#098658]1[/COLOR]] = [COLOR=#098658]0.0[/COLOR];
    [COLOR=#001080]machine[/COLOR].[COLOR=#001080]origins[/COLOR][i].[COLOR=#001080]pt[/COLOR][[COLOR=#098658]2[/COLOR]] = [COLOR=#098658]0.0[/COLOR];
  }

  [COLOR=#001080]machine[/COLOR].[COLOR=#001080]move_rate[/COLOR] = [COLOR=#098658]0.0[/COLOR];[COLOR=#008000]  // initialize all the operating parameters of the machine.[/COLOR]
  [COLOR=#001080]machine[/COLOR].[COLOR=#001080]traverse_rate[/COLOR] = [COLOR=#098658]0.0[/COLOR];
  [COLOR=#001080]machine[/COLOR].[COLOR=#001080]feed_rate[/COLOR] = [COLOR=#098658]0.0[/COLOR];
  [COLOR=#001080]machine[/COLOR].[COLOR=#001080]spindle_speed[/COLOR] = [COLOR=#098658]0.0[/COLOR];
  [COLOR=#001080]machine[/COLOR].[COLOR=#001080]surface_speed[/COLOR] = [COLOR=#098658]0.0[/COLOR];
  [COLOR=#001080]machine[/COLOR].[COLOR=#001080]tool_index[/COLOR] = [COLOR=#098658]0[/COLOR];
  [COLOR=#001080]machine[/COLOR].[COLOR=#001080]origin_index[/COLOR] = [COLOR=#098658]0[/COLOR];
  [COLOR=#001080]machine[/COLOR].[COLOR=#001080]state[/COLOR].[COLOR=#001080]use_ramp[/COLOR] = [COLOR=#098658]0[/COLOR];
  [COLOR=#001080]machine[/COLOR].[COLOR=#001080]state[/COLOR].[COLOR=#001080]modal[/COLOR] = [COLOR=#098658]0[/COLOR];
  [COLOR=#001080]machine[/COLOR].[COLOR=#001080]state[/COLOR].[COLOR=#001080]abs_mode[/COLOR] = [COLOR=#098658]0[/COLOR];
  [COLOR=#001080]machine[/COLOR].[COLOR=#001080]state[/COLOR].[COLOR=#001080]use_tool_comp[/COLOR] = [COLOR=#098658]0[/COLOR];
  [COLOR=#001080]machine[/COLOR].[COLOR=#001080]state[/COLOR].[COLOR=#001080]abs_mode[/COLOR] = [COLOR=#098658]0[/COLOR];
  [COLOR=#001080]machine[/COLOR].[COLOR=#001080]state[/COLOR].[COLOR=#001080]units_type[/COLOR] = DEFAULT_MACHINE_UNITS;

  [COLOR=#001080]machine[/COLOR].[COLOR=#001080]xyz_position[/COLOR][[COLOR=#098658]0[/COLOR]] = [COLOR=#098658]0.0[/COLOR];[COLOR=#008000]  // initialize all the absolute positions of each axis[/COLOR]
  [COLOR=#001080]machine[/COLOR].[COLOR=#001080]xyz_position[/COLOR][[COLOR=#098658]1[/COLOR]] = [COLOR=#098658]0.0[/COLOR];
  [COLOR=#001080]machine[/COLOR].[COLOR=#001080]xyz_position[/COLOR][[COLOR=#098658]2[/COLOR]] = [COLOR=#098658]0.0[/COLOR];
  [COLOR=#001080]machine[/COLOR].[COLOR=#001080]xyz_target[/COLOR][[COLOR=#098658]0[/COLOR]] = [COLOR=#098658]0.0[/COLOR];
  [COLOR=#001080]machine[/COLOR].[COLOR=#001080]xyz_target[/COLOR][[COLOR=#098658]1[/COLOR]] = [COLOR=#098658]0.0[/COLOR];
  [COLOR=#001080]machine[/COLOR].[COLOR=#001080]xyz_target[/COLOR][[COLOR=#098658]2[/COLOR]] = [COLOR=#098658]0.0[/COLOR];
  [COLOR=#001080]machine[/COLOR].[COLOR=#001080]abc_position[/COLOR][[COLOR=#098658]0[/COLOR]] = [COLOR=#098658]0.0[/COLOR];
  [COLOR=#001080]machine[/COLOR].[COLOR=#001080]abc_position[/COLOR][[COLOR=#098658]1[/COLOR]] = [COLOR=#098658]0.0[/COLOR];
  [COLOR=#001080]machine[/COLOR].[COLOR=#001080]abc_position[/COLOR][[COLOR=#098658]2[/COLOR]] = [COLOR=#098658]0.0[/COLOR];
  [COLOR=#001080]machine[/COLOR].[COLOR=#001080]abc_target[/COLOR][[COLOR=#098658]0[/COLOR]] = [COLOR=#098658]0.0[/COLOR];
  [COLOR=#001080]machine[/COLOR].[COLOR=#001080]abc_target[/COLOR][[COLOR=#098658]1[/COLOR]] = [COLOR=#098658]0.0[/COLOR];
  [COLOR=#001080]machine[/COLOR].[COLOR=#001080]abc_target[/COLOR][[COLOR=#098658]2[/COLOR]] = [COLOR=#098658]0.0[/COLOR];
  [COLOR=#001080]machine[/COLOR].[COLOR=#001080]uvw_position[/COLOR][[COLOR=#098658]0[/COLOR]] = [COLOR=#098658]0.0[/COLOR];
  [COLOR=#001080]machine[/COLOR].[COLOR=#001080]uvw_position[/COLOR][[COLOR=#098658]1[/COLOR]] = [COLOR=#098658]0.0[/COLOR];
  [COLOR=#001080]machine[/COLOR].[COLOR=#001080]uvw_position[/COLOR][[COLOR=#098658]2[/COLOR]] = [COLOR=#098658]0.0[/COLOR];
  [COLOR=#001080]machine[/COLOR].[COLOR=#001080]uvw_target[/COLOR][[COLOR=#098658]0[/COLOR]] = [COLOR=#098658]0.0[/COLOR];
  [COLOR=#001080]machine[/COLOR].[COLOR=#001080]uvw_target[/COLOR][[COLOR=#098658]1[/COLOR]] = [COLOR=#098658]0.0[/COLOR];
  [COLOR=#001080]machine[/COLOR].[COLOR=#001080]uvw_target[/COLOR][[COLOR=#098658]2[/COLOR]] = [COLOR=#098658]0.0[/COLOR];
}
[COLOR=#008000]//------------------------------------------------------------------------------[/COLOR]

[/FONT][/COLOR]
 
Back
Top