M98/M99 subprograms

This patch implements subprograms as defined with a bare numbered
O-word, called with `M98` and returned from with `M99`.  This common
style of subprogram is used in Fanuc, Haas and other controllers.

 ## Implementation

In essence, `M98` and `M99` are O-words.  O-words are handled
specially compared to M- and G-words, both when being read
(e.g. parsed earlier in interp loop than other codes) and when being
executed (e.g. own translation unit with functions for searching and
seeking across g-code file blocks).  Therefore, they are implemented
next to other O-word code, and where possible they share the same read
and execute flow.  There is a major semantic difference compared to
traditional rs274ngc subroutines: Execution starts at the beginning of
the file and continues right into a program definition rather than
skipping past.  Such a program definition at the beginning of the
file is the 'main program', although not treated specially by the
interpreter, and `M98` may only call subprograms following the main
program.

In the interpreter's read phase, `M98` call and `M99` return are
handled in `read_o()` at the same time as O-words in `interp_read.cc`.
`M98` is handled much like `O call`.

During execution, `M98 P1` is quite similar to `O1 call`, and they
share the `Interp::execute_call()` function in `interp_o_word.cc`.
Still, `M98` must be distinguished with the special `call_type =
CT_NGC_M98_SUB` to signal to `execute_call()` and `unwind_call()` that
parameters `#1` through `#30` are global.  The call type is also used
to prevent programmers from mixing e.g. `O sub` with `M98` and `M99`.

When `M98` is followed by an L-word (repeat count), it maintains a
loop counter in the parent context `m98_loop_counter` field, and
special logic in `execute_call()` manages call return block location
for iteration.

An `M99` in the main program (top-level call stack) has a special
meaning.  There is no subprogram to return from, so instead it means
to skip back to the beginning of the file and resume execution; in
other words, loop endlessly over the program.  In this case, `M99` is
treated like an M-word handled by `read_m()`, and shares modal group 4
and `convert_stop()` with `M02` and `M30`.

The interpreter cannot handle endless loops because it would queue
canon commands indefinitely without a program end or a queue buster,
and never issue them to task for execution.  Therefore the interpreter
distinguishes the following two subcases of the `M99` endless loop:

- Task:  During real execution of a program, an `M99` in the top-level
  context is treated like a queue-buster.  The interpreter queue is
  flushed to motion (after queuing any link segments) before looping
  back to the program beginning.  Task enables this special behavior
  by calling `interp.set_loop_on_main_m99(true)`.

- SAI, preview, etc.:  When not actually executing, an `M99` in the
  top-level context is treated like an `M30`, program stop.  The
  assumption is that a single loop will be sufficient for
  non-execution use cases, such as to render a tool path preview or
  check the canon commands generated by a program.  This is the
  default behavior, also explicitly set by calling
  `interp.set_loop_on_main_m99(false)`.

 ## Fanuc and rs274ngc sub call coexistence

The syntax differences create no parsing ambiguities.  During
conversion the two styles share some code paths, where any differences
are handled by the O-word (or M-word) type and call style.

Additional checks ban mixing rs274ngc and Fanuc sub blocks within one
call/return cycle in hopes of reducing confusion arising from careless
mixing and the unintended side-effects of style differences.

If there is reason to disable Fanuc subroutines, do so by placing
`DISABLE_FANUC_STYLE_SUB = 1` in the `[RS274NGC]` section of the
`.ini` file.

Signed-off-by: John Morris <john@zultron.com>
This commit is contained in:
John Morris 2015-10-05 16:01:29 -05:00
parent 098ef6ef59
commit 176ba83655
79 changed files with 2210 additions and 124 deletions

View file

@ -32,6 +32,7 @@
|<<mcode:m71,M71>> | Invalidate Stored Modal State
|<<mcode:m72,M72>> | Restore Modal State
|<<mcode:m73,M73>> | Save Autorestore Modal State
|<<mcode:m98-m99,M98 M99>> | Call and Return From Subprogram
|<<mcode:m100-m199,M100-M199>> | User Defined M-Codes
|========================================
@ -608,6 +609,13 @@ o<showstate> call
m2
----
[[mcode:m98-m99]]
== M98 and M99 ==
The interpreter supports Fanuc-style main- and sub-programs with the
'M98' and 'M99' M-codes. See <<ocode:fanuc-style-programs,Fanuc-Style
Programs>>.
=== Selectively Restoring Modal State
Executing an 'M72' or returning from a subroutine which contains an

View file

@ -108,6 +108,128 @@ of parameters above #30 and those changes will be visible to the
calling code. Subroutines may also change the value of global named
parameters.
[[ocode:fanuc-style-programs]]
=== Fanuc-Style Numbered Programs ===
(((Subroutines, M98, M99)))
Numbered programs (both main and subprograms), the 'M98' call and
'M99' return M-codes, and their respective semantic differences are an
alternative to the rs274ngc subroutines described above, provided for
compatibility with Fanuc and other machine controllers.
Numbered programs are enabled by default, and may be disabled by
placing `DISABLE_FANUC_STYLE_SUB = 1` in the `[RS274NGC]` section
of the `.ini` file.
[NOTE]
Numbered main and subprogram definitions and calls differ from
traditional rs274ngc both in syntax and execution. To reduce the
possibility of confusion, the interpreter will raise an error if
definitions of one style are mixed with calls of another.
.Numbered Subprogram Simple Example
[source,{ngc}]
----
o1 (Example 1) ; Main program 1, "Example 1"
M98 P100 ; Call subprogram 100
M30 ; End main program
o100 ; Beginning of subprogram 100
G53 G0 X0 Y0 Z0 ; Rapid move to machine home
M99 ; Return from subprogram 100
----
.`o1 (Title)`
The optional main program beginning block gives the main program the
number `1`. Some controllers treat an optional following
parenthesized comment as a program title, `Example 1` in this example,
but this has no special meaning in the rs274ngc interpreter.
.`M98 P- <L\->`
Call a numbered subprogram. The block `M98 P100` is analogous to the
traditional `o100 call` syntax, but may only be used to call a
following numbered subprogram defined with `o100`...`M99`. An
optional 'L'-word specifies a loop count.
.`M30`
The main program must be terminated with `M02` or `M30` (or `M99`; see
below).
.`O-` subprogram definition start
Marks the start of a numbered subprogram definition. The block `O100`
is similar to `o100 sub`, except that it must be placed later in the
file than the `M98 P100` calling block.
.`M99` return from numbered subroutine
The block `M99` is analogous to the traditional `o100 endsub` syntax,
but may only terminate a numbered program (`o100` in this example),
and may not terminate a subroutine beginning with the `o100 sub`
syntax.
The `M98` subprogram call differs from rs274ngc `O call` in the
following ways:
* The numbered subprogram must follow the `M98` call in the program
file. The interpreter will throw an error if the subprogram precedes
the call block.
* Parameters `#1`, `#2`, ..., `#30` are global and accessible in
numbered subprograms, similar to higher-numbered parameters in
traditional style calls. Modifications to these parameters within a
subprogram are global modifications, and will be persist after
subprogram return.
* `M98` subprogram calls have no return value.
* `M98` subprogram call blocks may contain an optional L-word
specifying a loop repeat count. Without the L-word, the subprogram
will execute once only (equivalent to `M98 L1`). An `M98 L0` block
will not execute the subprogram.
In rare cases, the `M99` M-code may be used to terminate the main
program, where it indicates an 'endless program'. When the
interpreter reaches an `M99` in the main program, it will skip back to
the beginning of the file and resume execution at the first line. An
example use of an endless program is in a machine warm-up cycle; a
block delete program end `/M30` block might be used to stop the cycle
at a tidy point when the operator is ready.
.Numbered Subprogram Full Example
[source,{ngc}]
----
O1 ; Main program 1
#1 = 0
(PRINT,X MAIN BEGIN: 1=#1)
M98 P100 L5 ; Call subprogram 100
(PRINT,X MAIN END: 1=#1)
M30 ; End main program
O100 ; Subprogram 100
#1 = [#1 + 1]
M98 P200 L5 ; Call subprogram 200
(PRINT,>> O100: #1)
M99 ; Return from Subprogram 100
O200 ; Subprogram 200
#1 = [#1 + 0.01]
(PRINT,>>>> O200: #1)
M99 ; Return from Subprogram 200
----
In this example, parameter `#1` is initialized to `0`. Subprogram
`O100` is called five times in a loop. Nested within each call to
`O100`, subprogram `O200` is called five times in a loop, for 25 times
total.
Note that parameter `#1` is global. At the end of the main program,
after updates within `O100` and `O200`, its value will equal `5.25`.
[[ocode:looping]]
== Looping
(((Subroutines, Looping)))

View file

@ -93,6 +93,7 @@ public:
void active_m_codes(int active_mcodes[ACTIVE_M_CODES]);
void active_settings(double active_settings[ACTIVE_SETTINGS]);
void set_loglevel(int level);
void set_loop_on_main_m99(bool state);
FILE *f;
char filename[PATH_MAX];
};
@ -723,5 +724,6 @@ void Canterp::active_g_codes(int gees[]) { std::fill(gees, gees + ACTIVE_G_CODES
void Canterp::active_m_codes(int emms[]) { std::fill(emms, emms + ACTIVE_M_CODES, 0); }
void Canterp::active_settings(double sets[]) { std::fill(sets, sets + ACTIVE_SETTINGS, 0.0); }
void Canterp::set_loglevel(int level) {}
void Canterp::set_loop_on_main_m99(bool state) {}
InterpBase *makeInterp() { return new Canterp; }

View file

@ -132,7 +132,8 @@ extension of the language for pallet shuttle and stop. This version has
no codes related to axis clamping.
The groups are:
group 4 = {m0,m1,m2,m30,m60} - stopping
group 4 = {m0,m1,m2,m30,m60,
m99} - stopping
group 5 = {m62,m63,m64,m65, - turn I/O point on/off
m66} - wait for Input
group 6 = {m6,m61} - tool change
@ -154,9 +155,9 @@ const int Interp::_ems[] = {
-1, -1, -1, -1, -1, -1, -1, -1, 9, 9, // 49
9, 9, 9, 9, -1, -1, -1, -1, -1, -1, // 59
4, 6, 5, 5, 5, 5, 5, 5, 5, -1, // 69
7, 7, 7, 7, -1, -1, -1, -1, -1, -1, // 79
7, 7, 7, 7, -1, -1, -1, -1, -1, -1, // 79
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 89
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 99
-1, -1, -1, -1, -1, -1, -1, -1, -1, 4, // 99
10, 10, 10, 10, 10, 10, 10, 10, 10, 10, //109
10, 10, 10, 10, 10, 10, 10, 10, 10, 10, //119
10, 10, 10, 10, 10, 10, 10, 10, 10, 10, //129

View file

@ -52,6 +52,7 @@ public:
virtual void active_m_codes(int active_mcodes[ACTIVE_M_CODES]) = 0;
virtual void active_settings(double active_settings[ACTIVE_SETTINGS]) = 0;
virtual void set_loglevel(int level) = 0;
virtual void set_loop_on_main_m99(bool state) = 0;
};
InterpBase *interp_from_shlib(const char *shlib);

View file

@ -293,8 +293,11 @@ int Interp::check_other_codes(block_pointer block) //!< pointer to a block
(block->g_modes[0] != G_10) &&
(block->g_modes[7] != G_41) && (block->g_modes[7] != G_41_1) &&
(block->g_modes[7] != G_42) && (block->g_modes[7] != G_42_1) &&
(block->m_modes[5] != 66)),
_("L word with no G10, cutter compensation, canned cycle, digital/analog input, or NURBS code"));
(block->m_modes[5] != 66) &&
(block->o_type != M_98) // m98 repeat
),
_("L word with no G10, cutter compensation, canned cycle, "
"digital/analog input, M98 or NURBS code"));
}
if (block->p_flag) {
@ -305,9 +308,11 @@ int Interp::check_other_codes(block_pointer block) //!< pointer to a block
(block->m_modes[9] != 50) && (block->m_modes[9] != 51) && (block->m_modes[9] != 52) &&
(block->m_modes[9] != 53) && (block->m_modes[5] != 62) && (block->m_modes[5] != 63) &&
(block->m_modes[5] != 64) && (block->m_modes[5] != 65) && (block->m_modes[5] != 66) &&
(block->m_modes[7] != 19) && (block->user_m != 1)),
(block->m_modes[7] != 19) && (block->user_m != 1) &&
(block->o_type != M_98)),
_("P word with no G2 G3 G4 G10 G64 G5 G5.2 G76 G82 G86 G88 G89"
" or M50 M51 M52 M53 M62 M63 M64 M65 M66 or user M code to use it"));
" or M50 M51 M52 M53 M62 M63 M64 M65 M66 M98 "
"or user M code to use it"));
int p_value = round_to_int(block->p_number);
CHKS(((motion == G_2 || motion == G_3 || (block->m_modes[7] == 19)) &&
fabs(p_value - block->p_number) > 0.001),

View file

@ -4035,12 +4035,16 @@ int Interp::convert_spindle_mode(block_pointer block, setup_pointer settings)
Returned Value: int
When an m2 or m30 (program_end) is encountered, this returns INTERP_EXIT.
If the code is not m0, m1, m2, m30, or m60, this returns
NCE_BUG_CODE_NOT_M0_M1_M2_M30_M60
M99 main program endless loop:
if looping is disabled (default, not in task), return INTERP_EXIT;
else in task, return INTERP_EXECUTE_FINISH.
M99 return from subprogram is not handled here, and raises an error.
If the code is not m0, m1, m2, m30, m60, or m99 this returns
NCE_BUG_CODE_NOT_M0_M1_M2_M30_M60_M99
Otherwise, it returns INTERP_OK.
Side effects:
An m0, m1, m2, m30, or m60 in the block is executed.
An m0, m1, m2, m30, m60 or m99 in the block is executed.
For m0, m1, and m60, this makes a function call to the PROGRAM_STOP
canonical machining function (which stops program execution).
@ -4049,6 +4053,16 @@ Side effects:
For m2 and m30, this resets the machine and then calls PROGRAM_END.
In addition, m30 calls PALLET_SHUTTLE.
For m99 main program endless looping in task, this returns control
to the beginning of the file and outputs any linked segments to the
interp list. The INTERP_EXECUTE_FINISH return code causes any
commands in the interp list to be issued so that the endless loop
doesn't result in an infinite queue.
For m99 main program endless looping elsewhere, especially preview
where endless looping is not desired, this behaves as m2 and m30
below.
Called by: execute_block.
This handles stopping or ending the program (m0, m1, m2, m30, m60)
@ -4103,6 +4117,11 @@ int Interp::convert_stop(block_pointer block, //!< pointer to a block of RS27
CHP(move_endpoint_and_flush(settings, cx, cy));
dequeue_canons(settings);
// M99 as subroutine return is handled in interp_o_word.cc
// convert_control_functions()
CHKS((block->m_modes[4] == 99 && settings->call_level > 0),
(_("Bug: Reached convert_stop() from M99 as subprogram return")));
if (block->m_modes[4] == 0) {
PROGRAM_STOP();
} else if (block->m_modes[4] == 60) {
@ -4110,7 +4129,16 @@ int Interp::convert_stop(block_pointer block, //!< pointer to a block of RS27
PROGRAM_STOP();
} else if (block->m_modes[4] == 1) {
OPTIONAL_PROGRAM_STOP();
} else if ((block->m_modes[4] == 2) || (block->m_modes[4] == 30)) { /* reset stuff here */
} else if (block->m_modes[4] == 99 && _setup.loop_on_main_m99) {
// Fanuc-style M99 main program endless loop
logDebug("M99 main program endless loop");
loop_to_beginning(settings); // return control to beginning of file
FINISH(); // Output any final linked segments
return INTERP_EXECUTE_FINISH; // tell task to issue any queued commands
} else if ((block->m_modes[4] == 2) || (block->m_modes[4] == 30) ||
(block->m_modes[4] == 99 && !_setup.loop_on_main_m99)
) { /* reset stuff here */
/*1*/
settings->current_x += settings->origin_offset_x;
settings->current_y += settings->origin_offset_y;
@ -4230,7 +4258,7 @@ int Interp::convert_stop(block_pointer block, //!< pointer to a block of RS27
unwind_call(INTERP_EXIT, __FILE__,__LINE__,__FUNCTION__);
return INTERP_EXIT;
} else
ERS(NCE_BUG_CODE_NOT_M0_M1_M2_M30_M60);
ERS(NCE_BUG_CODE_NOT_M0_M1_M2_M30_M60_M99);
return INTERP_OK;
}

View file

@ -280,7 +280,8 @@ int Interp::execute_block(block_pointer block, //!< pointer to a block of RS27
}
CHP(convert_m(block, settings));
CHP(convert_g(block, settings));
if ((block->m_modes[4] != -1) && ONCE(STEP_MGROUP4)) { /* converts m0, m1, m2, m30, or m60 */
/* convert m0, m1, m2, m30, m60, or (when main program loops disabled) m99 */
if ((block->m_modes[4] != -1) && ONCE(STEP_MGROUP4)) {
if (STEP_REMAPPED_IN_BLOCK(block, STEP_MGROUP4)) {
status = convert_remapped_code(block,settings,STEP_MGROUP4,'M',block->m_modes[4]);
} else {

View file

@ -174,6 +174,9 @@ enum SPINDLE_MODE { CONSTANT_RPM, CONSTANT_SURFACE };
#define O_return 13
#define O_repeat 14
#define O_endrepeat 15
#define M_98 16
#define M_99 17
#define O_ 18
// G Codes are symbolic to be dialect-independent in source code
#define G_0 0
@ -528,7 +531,9 @@ enum call_states {
// detail for O_call; tags the frame
enum call_types {
CT_NONE, // not in a call
CT_NGC_OWORD_SUB, // no restartable Python code involved
CT_NGC_M98_SUB, // like above; Fanuc-style, pass in params #1..#30
CT_PYTHON_OWORD_SUB, // restartable Python code may be involved
CT_REMAP, // restartable Python code may be involved
};
@ -571,6 +576,7 @@ typedef struct context_struct {
int sequence_number; // location (line number) in file
const char *filename; // name of file for this context
const char *subName; // name of the subroutine (oword)
int m98_loop_counter; // loop counter for Fanuc-style sub calls
double saved_params[INTERP_SUB_PARAMS];
parameter_map named_params;
unsigned char context_status; // see CONTEXT_ defines below
@ -775,7 +781,12 @@ typedef struct setup_struct
bool lathe_diameter_mode; //Lathe diameter mode (g07/G08)
bool mdi_interrupt;
int feature_set;
int feature_set;
int disable_fanuc_style_sub;
// M99 in main is treated as program end by default; this causes
// control to skip to beginning of file
bool loop_on_main_m99;
#define FEATURE(x) (_setup.feature_set & FEATURE_ ## x)
#define FEATURE_RETAIN_G43 0x00000001

View file

@ -92,11 +92,16 @@ int Interp::control_save_offset(block_pointer block, /* pointer to a bloc
logOword("Entered:%s for o_name:|%s|", name, block->o_name);
if (control_find_oword(block, settings, &op) == INTERP_OK) {
// already exists
ERS(_("File:%s line:%d redefining sub: o|%s| already defined in file:%s"),
settings->filename, settings->sequence_number,
block->o_name,
op->filename);
if (settings->sequence_number -1 == op->sequence_number)
// hit this definition before; must be in illegal location
ERS(_("File:%s line:%d sub: o|%s| found in illegal location"),
settings->filename, settings->sequence_number, block->o_name);
else
// already exists
ERS(_("File:%s line:%d redefining sub: o|%s| already defined in file:%s"),
settings->filename, settings->sequence_number,
block->o_name,
op->filename);
}
offset new_offset;
@ -146,8 +151,10 @@ const char *o_ops[] = {
"O_return",
"O_repeat",
"O_endrepeat",
"O_continue_call",
"O_pyreturn",
"M_98",
"M_99",
"O_",
};
const char *call_statenames[] = {
@ -159,7 +166,9 @@ const char *call_statenames[] = {
};
const char *call_typenames[] = {
"CT_NGC_OWORD_SUB",
"CT_NONE",
"CT_NGC_OWORD_SUB",
"CT_NGC_M98_SUB",
"CT_PYTHON_OWORD_SUB",
"CT_REMAP",
};
@ -184,32 +193,36 @@ int Interp::execute_call(setup_pointer settings,
switch (call_type) {
case CT_NONE:
ERS("BUG: execute_call(): arrived with call_type=CT_NONE");
break;
case CT_NGC_OWORD_SUB:
// copy parameters from context
// save old values of parameters
// save current file position in context
case CT_NGC_M98_SUB:
// if we were skipping, no longer
if (settings->skipping_o) {
logOword("case O_call -- no longer skipping to:|%s|",
logOword("case O_call/M_98 -- no longer skipping to:|%s|",
settings->skipping_o);
settings->skipping_o = NULL;
}
for(i = 0; i < INTERP_SUB_PARAMS; i++) {
previous_frame->saved_params[i] =
settings->parameters[i + INTERP_FIRST_SUBROUTINE_PARAM];
settings->parameters[i + INTERP_FIRST_SUBROUTINE_PARAM] =
eblock->params[i];
}
// if the previous file was NULL, mark positon as -1 so as not to
// reopen it on return.
if (settings->file_pointer == NULL) {
// copy parameters from context
// save old values of parameters
if (call_type != CT_NGC_M98_SUB) // M98: pass #1..#30 from parent
for (i = 0; i < INTERP_SUB_PARAMS; i++) {
previous_frame->saved_params[i] =
settings->parameters[i + INTERP_FIRST_SUBROUTINE_PARAM];
settings->parameters[i + INTERP_FIRST_SUBROUTINE_PARAM] =
eblock->params[i];
}
// Set up return to next block (may be overridden by M98)
if (settings->file_pointer == NULL)
// if the previous file was NULL, mark positon as -1 so as not to
// reopen it on return.
previous_frame->position = -1;
} else {
else
previous_frame->position = ftell(settings->file_pointer);
}
// save return location
previous_frame->filename = strstore(settings->filename);
previous_frame->sequence_number = settings->sequence_number;
logOword("saving return location[cl=%d]: %s:%d offset=%ld",
@ -226,12 +239,39 @@ int Interp::execute_call(setup_pointer settings,
OVERRIDE_READONLY));
}
// transfer control
if (control_back_to(eblock, settings) == INTERP_ERROR) {
// M98 w/ L-word: Handle looping
if (eblock->o_type == M_98 && eblock->l_flag) {
// Set up loop counter
// Loop count from L-word
if (previous_frame->m98_loop_counter == -1)
// If m98_loop_counter == -1, this is a new loop
previous_frame->m98_loop_counter = round_to_int(eblock->l_number);
logOword("Looping on O%s; remaining: %d",
eblock->o_name, previous_frame->m98_loop_counter);
// if repeats remain, set up another loop
previous_frame->m98_loop_counter--;
if (previous_frame->m98_loop_counter > 0) {
// Set return location to repeat this block for next
// iteration
previous_frame->position = eblock->offset;
} else
// No loops remain; reset loop counter
previous_frame->m98_loop_counter = -1;
}
if (eblock->o_type == M_98 && eblock->l_flag && eblock->l_number == 0)
logOword("M98 L0 instruction; skipping call");
else if (control_back_to(eblock, settings) == INTERP_ERROR) {
settings->call_level--;
ERS(NCE_UNABLE_TO_OPEN_FILE,eblock->o_name);
return INTERP_ERROR;
}
break;
case CT_PYTHON_OWORD_SUB:
@ -389,13 +429,16 @@ int Interp::execute_return(setup_pointer settings, context_pointer current_frame
}
// fall through to normal NGC return handling
case CT_NGC_OWORD_SUB:
case CT_NGC_M98_SUB:
case CT_NONE: // sub definition
if (settings->call_level != 0) {
// restore subroutine parameters.
for(int i = 0; i < INTERP_SUB_PARAMS; i++) {
settings->parameters[i+INTERP_FIRST_SUBROUTINE_PARAM] =
previous_frame->saved_params[i];
}
if (call_type != CT_NGC_M98_SUB) // M98: pass #1..#30 from parent
for(int i = 0; i < INTERP_SUB_PARAMS; i++) {
settings->parameters[i+INTERP_FIRST_SUBROUTINE_PARAM] =
previous_frame->saved_params[i];
}
// file at this level was marked as closed, so dont reopen.
if (previous_frame->position == -1) {
@ -456,6 +499,21 @@ int Interp::execute_return(setup_pointer settings, context_pointer current_frame
return status;
}
// this is executed for m99 in the main program, signifying an endless
// loop; m99 main program endless loop is handled in
// interp_convert.cc, but because this is like an O-word function
// skipping around the file, it's placed here instead.
void Interp::loop_to_beginning(setup_pointer settings)
{
logOword("loop_to_beginning state=%s file=%s",
call_statenames[settings->call_state],
settings->filename);
// scroll back to beginning of file/first block
fseek(settings->file_pointer, 0, SEEK_SET);
settings->sequence_number = 0;
}
//
// TESTME!!! MORE THOROUGHLY !!!KL
//
@ -603,7 +661,8 @@ int Interp::enter_context(setup_pointer settings, block_pointer block)
frame->py_returned_int = 0;
frame->py_returned_double = 0.0;
frame->py_return_type = -1;
frame->call_type = block->call_type; // distinguish call frames: oword,python,remap
// distinguish call frames: oword,m99,python,remap
frame->call_type = block->call_type;
return INTERP_OK;
}
@ -663,7 +722,8 @@ int Interp::convert_control_functions(block_pointer block, // pointer to a block
logOword("skipping to line: |%s|", settings->skipping_o);
return INTERP_OK;
}
if (settings->skipping_to_sub && (block->o_type != O_sub)) {
if (settings->skipping_to_sub && (block->o_type != O_sub)
&& (block->o_type != O_)) {
logOword("skipping to sub: |%s|", settings->skipping_to_sub);
return INTERP_OK;
}
@ -679,8 +739,23 @@ int Interp::convert_control_functions(block_pointer block, // pointer to a block
break;
case O_sub:
// if the level is not zero, this is a call
// not the definition
case O_:
current_frame = &settings->sub_context[settings->call_level];
// Mixing Fanuc- and rs274ngc-style sub calls & defs is not allowed:
// - Fanuc: 'O....' subprogram must be called with 'M98'
CHKS((block->o_type == O_ &&
current_frame->call_type != CT_NGC_M98_SUB &&
current_frame->call_type != CT_NONE),
"Fanuc 'O....' subroutine must be called with 'M98'");
// - rs274ngc: 'O.... sub' subprogram must be called with 'O.... call'
CHKS((block->o_type == O_sub &&
current_frame->call_type != CT_NGC_OWORD_SUB &&
current_frame->call_type != CT_PYTHON_OWORD_SUB &&
current_frame->call_type != CT_REMAP &&
current_frame->call_type != CT_NONE),
"'O.... sub' subroutine must be called with 'O.... call'");
// if we were skipping, no longer
if (settings->skipping_o) {
logOword("sub(o_|%s|) was skipping to here", settings->skipping_o);
@ -691,6 +766,14 @@ int Interp::convert_control_functions(block_pointer block, // pointer to a block
}
settings->skipping_to_sub = NULL; // this IS our block number
if (block->o_type == O_) {
// Done: continue executing into Fanuc-style programs w/o skipping
logOword("Entering Fanuc-style program number %s", block->o_name);
break;
}
// if the level is not zero, this is a call
// not the definition
if (settings->call_level != 0) {
logOword("call:%f:%f:%f",
settings->parameters[1],
@ -698,7 +781,8 @@ int Interp::convert_control_functions(block_pointer block, // pointer to a block
settings->parameters[3]);
} else {
// a definition. We're on the O<name> sub line.
logOword("started a subroutine defn: %s",block->o_name);
logOword("started a rs274-style sub-program defn: %s",
block->o_name);
CHKS((settings->defining_sub == 1), NCE_NESTED_SUBROUTINE_DEFN);
CHP(control_save_offset( block, settings));
@ -713,6 +797,12 @@ int Interp::convert_control_functions(block_pointer block, // pointer to a block
case O_endsub:
case O_return:
case M_99:
// For M99, this only handles return from a subprogram
CHKS((block->o_type == M_99 && settings->call_level == 0),
"Bug: Reached convert_control_functions() "
"from M99 in main program");
if ((settings->call_level == 0) &&
(settings->sub_name == NULL)) {
@ -720,15 +810,27 @@ int Interp::convert_control_functions(block_pointer block, // pointer to a block
OERR(_("%d: not in a subroutine definition: '%s'"),
settings->sequence_number, settings->linetext);
}
current_frame = &settings->sub_context[settings->call_level];
// 'O....' sub defn must be closed with 'M99'
CHKS((current_frame->call_type == CT_NGC_M98_SUB &&
block->o_type != M_99),
"Fanuc 'O....' subroutine definition must end with 'M99'");
// 'O.... sub' sub defn must be closed with 'O.... endsub' or
// 'O.... return'
CHKS((current_frame->call_type == CT_NGC_OWORD_SUB &&
block->o_type != O_endsub && block->o_type != O_return),
"'O.... endsub' or 'O.... return' must follow 'O.... sub' "
"subroutine definition");
// proper label semantics (only refer to defined sub, within sub defn etc)
// is handled in read_o() for return & endsub
current_frame = &settings->sub_context[settings->call_level];
CHP(execute_return(settings, current_frame,
current_frame->call_type));
break;
case O_call:
case M_98:
// only enter new frame if not reexecuting a Python handler
// which returned INTERP_EXECUTE_FINISH
if (settings->call_state == CS_NORMAL) {

View file

@ -771,6 +771,7 @@ int Interp::read_items(block_pointer block, //!< pointer to a block being f
double *parameters) //!< array of system parameters
{
int counter;
int m_number, m_counter; // for checking m98/m99 as o-words
int length;
length = strlen(line);
@ -783,10 +784,18 @@ int Interp::read_items(block_pointer block, //!< pointer to a block being f
CHP(read_n_number(line, &counter, block));
}
if (line[counter] == 'o')
/* Handle 'o' explicitly here. Default is
to read letters via pointer calls to related
reader functions. 'o' control lines have their
// Pre-check for M code, used in following logic
if (! (line[counter] == 'm' &&
read_integer_value(line, &(m_counter=counter+1), &m_number,
parameters) == INTERP_OK))
m_number = -1;
if (line[counter] == 'o' || m_number == 98 ||
(m_number == 99 && _setup.call_level > 0))
/* Handle 'o', 'm98' and 'm99' sub return (but not 'm99' endless
program) explicitly here. Default is to read letters via pointer
calls to related reader functions. 'o' control lines have their
own commands and command handlers. */
{
CHP(read_o(line, &counter, block, parameters));
@ -1492,65 +1501,125 @@ int Interp::read_o( /* ARGUMENTS */
char oNameBuf[LINELEN+1];
const char *subName;
char fullNameBuf[2*LINELEN+1];
int oNumber;
int oNumber, n;
extern const char *o_ops[];
CHKS((line[*counter] != 'o'), NCE_BUG_FUNCTION_SHOULD_NOT_HAVE_BEEN_CALLED);
if (line[*counter] == 'm' &&
read_integer_value(line, &(n=*counter+1), &oNumber,
parameters) == INTERP_OK) {
// m98 or m99 found
if (oNumber == 98) {
CHKS(_setup.disable_fanuc_style_sub,
"DISABLE_FANUC_STYLE_SUB set in .ini file, but found m98");
// changed spec so we now read an expression
// so... we can have a parameter contain a function pointer!
*counter += 1;
// Fanuc-style subroutine call with loop: "m98"
block->o_type = M_98;
*counter += 3;
logDebug("In: %s line:%d |%s|", name, block->line_number, line);
// Read P-word and L-word now
n = strlen(line);
while (*counter < n)
CHP(read_one_item(line, counter, block, parameters));
// P-word: convert to int and put in oNameBuf
CHKS(! block->p_flag, "Found 'm98' code with no P-word");
// (conversion code from read_integer_value)
n = (int) floor(block->p_number);
if ((block->p_number - n) > 0.9999) {
n = (int) ceil(block->p_number);
} else
CHKS((block->p_number - n) > 0.0001,
NCE_NON_INTEGER_VALUE_FOR_INTEGER);
sprintf(oNameBuf, "%d", n);
} else if (oNumber == 99) {
// Fanuc-style subroutine return: "m99"
if(line[*counter] == '<')
{
read_name(line, counter, oNameBuf);
}
else
{
CHP(read_integer_value(line, counter, &oNumber,
parameters));
sprintf(oNameBuf, "%d", oNumber);
}
// Error checks:
// - Fanuc-style subs disabled
CHKS(_setup.disable_fanuc_style_sub,
"DISABLE_FANUC_STYLE_SUB set in .ini file, but found m99");
// - Empty stack M99 (endless program) handled in read_m()
CHKS(_setup.defining_sub,
"Found 'M99' instead of 'O endsub' after 'O sub'");
// We stash the text the offset part of setup
// Fanuc-style subroutine return: "m99"
block->o_type = M_99;
*counter += 3;
// Subroutine name not provided in Fanuc syntax, so pull from
// context
strncpy(oNameBuf, _setup.sub_context[_setup.call_level].subName,
LINELEN+1);
} else
// any other m-code should have been handled by read_m()
OERR(_("%d: Bug: Non-m98/m99 M-code passed to read_o(): '%s'"),
_setup.sequence_number, _setup.linetext);
} else {
CHKS((line[*counter] != 'o'), NCE_BUG_FUNCTION_SHOULD_NOT_HAVE_BEEN_CALLED);
// rs274-style O-word
*counter += 1;
if(line[*counter] == '<')
{
read_name(line, counter, oNameBuf);
}
else
{
CHP(read_integer_value(line, counter, &oNumber,
parameters));
sprintf(oNameBuf, "%d", oNumber);
}
// We stash the text the offset part of setup
#define CMP(txt) (strncmp(line+*counter, txt, strlen(txt)) == 0 && (*counter += strlen(txt)))
// characterize the type of o-word
// characterize the type of o-word
if(CMP("sub"))
block->o_type = O_sub;
else if(CMP("endsub"))
block->o_type = O_endsub;
else if(CMP("call"))
block->o_type = O_call;
else if(CMP("do"))
block->o_type = O_do;
else if(CMP("while"))
block->o_type = O_while;
else if(CMP("repeat"))
block->o_type = O_repeat;
else if(CMP("if"))
block->o_type = O_if;
else if(CMP("elseif"))
block->o_type = O_elseif;
else if(CMP("else"))
block->o_type = O_else;
else if(CMP("endif"))
block->o_type = O_endif;
else if(CMP("break"))
block->o_type = O_break;
else if(CMP("continue"))
block->o_type = O_continue;
else if(CMP("endwhile"))
block->o_type = O_endwhile;
else if(CMP("endrepeat"))
block->o_type = O_endrepeat;
else if(CMP("return"))
block->o_type = O_return;
else
block->o_type = O_none;
if(CMP("sub"))
block->o_type = O_sub;
else if(CMP("endsub"))
block->o_type = O_endsub;
else if(CMP("call"))
block->o_type = O_call;
else if(CMP("do"))
block->o_type = O_do;
else if(CMP("while"))
block->o_type = O_while;
else if(CMP("repeat"))
block->o_type = O_repeat;
else if(CMP("if"))
block->o_type = O_if;
else if(CMP("elseif"))
block->o_type = O_elseif;
else if(CMP("else"))
block->o_type = O_else;
else if(CMP("endif"))
block->o_type = O_endif;
else if(CMP("break"))
block->o_type = O_break;
else if(CMP("continue"))
block->o_type = O_continue;
else if(CMP("endwhile"))
block->o_type = O_endwhile;
else if(CMP("endrepeat"))
block->o_type = O_endrepeat;
else if(CMP("return"))
block->o_type = O_return;
else if((line+*counter)[0] == '(' || (line+*counter)[0] == ';'
|| (line+*counter)[0] == 0) {
// Fanuc-style subroutine definition: "O2000" with no following args
CHKS(_setup.disable_fanuc_style_sub,
"DISABLE_FANUC_STYLE_SUB disabled in .ini file, but found "
"bare O-word");
block->o_type = O_;
} else
block->o_type = O_none;
}
logDebug("In: %s line:%d |%s| subroutine=|%s|",
name, block->line_number, line, oNameBuf);
// we now have it characterized
// now create the text of the oword
@ -1559,9 +1628,12 @@ int Interp::read_o( /* ARGUMENTS */
{
// the global cases first
case O_sub:
case O_:
case O_endsub:
case O_call:
case M_98:
case O_return:
case M_99:
block->o_name = strstore(oNameBuf);
logDebug("global case:|%s|", block->o_name);
break;
@ -1590,12 +1662,14 @@ int Interp::read_o( /* ARGUMENTS */
logDebug("o_type:%s o_name: %s line:%d %s", o_ops[block->o_type], block->o_name,
block->line_number, line);
if (block->o_type == O_sub)
if (block->o_type == O_sub || block->o_type == O_)
{
block->o_type = O_sub;
// Check we're not already defining a main- or sub-program
CHKS((_setup.defining_sub == 1), NCE_NESTED_SUBROUTINE_DEFN);
}
// in terms of execution endsub and return do the same thing
else if ((block->o_type == O_endsub) || (block->o_type == O_return))
else if ((block->o_type == O_endsub) || (block->o_type == O_return) ||
(block->o_type == M_99))
{
if ((_setup.skipping_o != 0) &&
(0 != strcmp(_setup.skipping_o, block->o_name))) {
@ -1603,7 +1677,7 @@ int Interp::read_o( /* ARGUMENTS */
}
// optional return value expression
if (line[*counter] == '[') {
if (block->o_type != M_99 && line[*counter] == '[') {
CHP(read_real_expression(line, counter, &value, parameters));
logOword("%s %s value %lf",
(block->o_type == O_endsub) ? "endsub" : "return",
@ -1660,6 +1734,12 @@ int Interp::read_o( /* ARGUMENTS */
block->params[param_cnt] = 0.0;
}
}
else if(block->o_type == M_98) {
// No params in M98 block (this could also be 30!)
block->param_cnt = 0;
// Distinguish from 'O.... call'
block->call_type = CT_NGC_M98_SUB;
}
else if(block->o_type == O_do)
{
block->o_type = O_do;
@ -1800,6 +1880,7 @@ int Interp::read_p(char *line, //!< string: line of RS274/NGC code being proce
CHKS((line[*counter] != 'p'), NCE_BUG_FUNCTION_SHOULD_NOT_HAVE_BEEN_CALLED);
*counter = (*counter + 1);
CHKS((block->p_number > -1.0), NCE_MULTIPLE_P_WORDS_ON_ONE_LINE);
CHP(read_real_value(line, counter, &value, parameters));
// FMP removed check for negatives, since we may want them for
// user-defined codes
@ -3026,7 +3107,7 @@ int Interp::read_text(
strcpy(line, raw_line);
CHP(close_and_downcase(line));
if ((line[0] == '%') && (line[1] == 0) && (_setup.percent_flag)) {
FINISH();
FINISH();
return INTERP_ENDFILE;
}
} else {

View file

@ -150,6 +150,8 @@ setup_struct::setup_struct() :
lathe_diameter_mode(0),
mdi_interrupt(0),
feature_set(0),
disable_fanuc_style_sub(false),
loop_on_main_m99(false),
on_abort_command(NULL),
init_once(0)
{

View file

@ -43,6 +43,7 @@ public:
// get ready to run
int init();
void set_loop_on_main_m99(bool state);
// load a tool table
int load_tool_table();
@ -517,6 +518,16 @@ public:
block_pointer block, /* pointer to a block of RS274/NGC instructions */
setup_pointer settings); /* pointer to machine settings */
int control_save_offset(
block_pointer block,
const char *o_name, /* o_name key */
setup_pointer settings);
int control_find_oword( /* ARGUMENTS */
const char *o_name, /* o-word name */
setup_pointer settings, /* pointer to machine settings */
offset_pointer *ppo);
int control_find_oword( /* ARGUMENTS */
block_pointer block, /* block pointer to get (o-word) name */
setup_pointer settings, /* pointer to machine settings */
@ -536,6 +547,7 @@ public:
//int execute_pycall(setup_pointer settings, const char *name, int call_phase);
int execute_call(setup_pointer settings, context_pointer current_frame, int call_type);
int execute_return(setup_pointer settings, context_pointer current_frame, int call_type);
void loop_to_beginning(setup_pointer settings);
//int execute_remap(setup_pointer settings, int call_phase); // remap call state machine
int handler_returned( setup_pointer settings,
context_pointer active_frame, const char *name, bool osub);

View file

@ -1004,6 +1004,13 @@ int Interp::init()
Error("invalid [RS274NGC]CENTER_ARC_RADIUS_TOLERANCE_MM in ini file\n");
}
// ini file m98/m99 subprogram default setting
inifile.Find(&_setup.disable_fanuc_style_sub,
"DISABLE_FANUC_STYLE_SUB",
"RS274NGC");
logDebug("init: DISABLE_FANUC_STYLE_SUB = %d",
_setup.disable_fanuc_style_sub);
// close it
inifile.Close();
}
@ -1221,6 +1228,12 @@ int Interp::init()
return INTERP_OK;
}
void Interp::set_loop_on_main_m99(bool state) {
// Enable/disable M99 main program endless looping
_setup.loop_on_main_m99 = state;
}
/***********************************************************************/
/*! Interp::load_tool_table
@ -1509,10 +1522,14 @@ int Interp::_read(const char *command) //!< may be NULL or a string to read
block_pointer eblock = &EXECUTING_BLOCK(_setup);
if ((_setup.call_state > CS_NORMAL) &&
(eblock->call_type > CT_NGC_OWORD_SUB) &&
(eblock->call_type != CT_NGC_OWORD_SUB) &&
(eblock->call_type != CT_NGC_M98_SUB) &&
(eblock->call_type != CT_NONE) &&
((eblock->o_type == O_call) ||
(eblock->o_type == M_98) ||
(eblock->o_type == O_return) ||
(eblock->o_type == O_endsub))) {
(eblock->o_type == O_endsub) ||
(eblock->o_type == M_99))) {
logDebug("read(): skipping read");
_setup.line_length = 0;
@ -1574,8 +1591,12 @@ int Interp::_read(const char *command) //!< may be NULL or a string to read
EXECUTING_BLOCK(_setup).o_type = 0;
}
}
} else if (read_status == INTERP_ENDFILE);
else
} else if (read_status == INTERP_ENDFILE) {
// If skipping but not defining the main program, we hit EOF
// before finding the sub we're looking for; error out
CHKS((_setup.skipping_o != NULL),
"Failed to find sub 'O%s' before EOF", _setup.skipping_o);
} else
ERP(read_status);
return read_status;
}
@ -1605,10 +1626,11 @@ int Interp::unwind_call(int status, const char *file, int line, const char *func
sub->subName = 0;
}
for(i=0; i<INTERP_SUB_PARAMS; i++) {
_setup.parameters[i+INTERP_FIRST_SUBROUTINE_PARAM] =
sub->saved_params[i];
}
if (sub->call_type != CT_NGC_M98_SUB) // M98: pass #1..#30 from parent
for(i=0; i<INTERP_SUB_PARAMS; i++) {
_setup.parameters[i+INTERP_FIRST_SUBROUTINE_PARAM] =
sub->saved_params[i];
}
// When called from Interp::close via Interp::reset, this one is NULL
if (!_setup.file_pointer) continue;
@ -2511,8 +2533,8 @@ const char *strstore(const char *s)
context_struct::context_struct()
: position(0), sequence_number(0), filename(""), subName(""),
context_status(0), call_type(0), py_return_type(0), py_returned_double(0),
py_returned_int(0)
context_status(0), call_type(0), py_return_type(0), py_returned_double(0),
py_returned_int(0), m98_loop_counter(-1)
{
memset(saved_params, 0, sizeof(saved_params));
memset(saved_g_codes, 0, sizeof(saved_g_codes));

View file

@ -38,7 +38,7 @@
#define NCE_BUG_CODE_NOT_G98_OR_G99 _("Bug code not g98 or g99")
#define NCE_BUG_CODE_NOT_IN_G92_SERIES _("Bug code not in g92 series")
#define NCE_BUG_CODE_NOT_IN_RANGE_G54_TO_G593 _("Bug code not in range g54 to g593")
#define NCE_BUG_CODE_NOT_M0_M1_M2_M30_M60 _("Bug code not m0 m1 m2 m30 m60")
#define NCE_BUG_CODE_NOT_M0_M1_M2_M30_M60_M99 _("Bug code not m0 m1 m2 m30 m60 m99")
#define NCE_BUG_DISTANCE_MODE_NOT_G90_OR_G91 _("Bug distance mode not g90 or g91")
#define NCE_BUG_FUNCTION_SHOULD_NOT_HAVE_BEEN_CALLED _("Bug function should not have been called")
#define NCE_BUG_IN_TOOL_RADIUS_COMP _("Bug in tool radius comp")

View file

@ -428,6 +428,8 @@ int emcTaskPlanInit()
waitFlag = 0;
int retval = interp.init();
// In task, enable M99 main program endless looping
interp.set_loop_on_main_m99(true);
if (retval > INTERP_MIN_ERROR) { // I'd think this should be fatal.
print_interp_error(retval);
} else {

View file

@ -623,9 +623,10 @@ interpret_again:
// throw the results away if we're supposed to
// read
// through it
if ((programStartLine < 0 ||
emcStatus->task.readLine < programStartLine) &&
emcTaskPlanLevel() == 0) {
if ( programStartLine != 0 &&
emcTaskPlanLevel() == 0 &&
( programStartLine < 0 ||
emcTaskPlanLine() <= programStartLine )) {
// we're stepping over lines, so check them
// for
// limits, etc. and clear then out

View file

@ -0,0 +1,14 @@
;Nested subroutine definition
O1 sub
G1 X0
O2 sub
G1 Y0
O2 endsub
O1 endsub
O1 call
M30
%

View file

@ -0,0 +1,43 @@
N..... USE_LENGTH_UNITS(CANON_UNITS_MM)
N..... SET_G5X_OFFSET(1, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000)
N..... SET_G92_OFFSET(0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000)
N..... SET_XY_ROTATION(0.0000)
N..... SET_FEED_REFERENCE(CANON_XYZ)
N..... COMMENT("A simple O sub example ")
N..... SET_FEED_RATE(40.0000)
N..... STRAIGHT_TRAVERSE(0.0000, 0.0000, 0.2500, 0.0000, 0.0000, 0.0000)
N..... COMMENT("interpreter: distance mode changed to incremental")
N..... STRAIGHT_TRAVERSE(1.0000, 0.0000, 0.2500, 0.0000, 0.0000, 0.0000)
N..... COMMENT("interpreter: distance mode changed to absolute")
N..... COMMENT("interpreter: retract mode set to r_plane")
N..... SET_MOTION_CONTROL_MODE(CANON_EXACT_PATH)
N..... STRAIGHT_TRAVERSE(1.0000, 0.0000, 0.2500, 0.0000, 0.0000, 0.0000)
N..... STRAIGHT_FEED(1.0000, 0.0000, -1.0000, 0.0000, 0.0000, 0.0000)
N..... STRAIGHT_TRAVERSE(1.0000, 0.0000, 0.2500, 0.0000, 0.0000, 0.0000)
N..... SET_MOTION_CONTROL_MODE(CANON_CONTINUOUS, 0.000000)
N..... COMMENT("interpreter: distance mode changed to incremental")
N..... STRAIGHT_TRAVERSE(2.0000, 0.0000, 0.2500, 0.0000, 0.0000, 0.0000)
N..... COMMENT("interpreter: distance mode changed to absolute")
N..... COMMENT("interpreter: retract mode set to r_plane")
N..... SET_MOTION_CONTROL_MODE(CANON_EXACT_PATH)
N..... STRAIGHT_TRAVERSE(2.0000, 0.0000, 0.2500, 0.0000, 0.0000, 0.0000)
N..... STRAIGHT_FEED(2.0000, 0.0000, -1.0000, 0.0000, 0.0000, 0.0000)
N..... STRAIGHT_TRAVERSE(2.0000, 0.0000, 0.2500, 0.0000, 0.0000, 0.0000)
N..... SET_MOTION_CONTROL_MODE(CANON_CONTINUOUS, 0.000000)
N..... COMMENT("interpreter: distance mode changed to incremental")
N..... STRAIGHT_TRAVERSE(3.0000, 0.0000, 0.2500, 0.0000, 0.0000, 0.0000)
N..... COMMENT("interpreter: distance mode changed to absolute")
N..... COMMENT("interpreter: retract mode set to r_plane")
N..... SET_MOTION_CONTROL_MODE(CANON_EXACT_PATH)
N..... STRAIGHT_TRAVERSE(3.0000, 0.0000, 0.2500, 0.0000, 0.0000, 0.0000)
N..... STRAIGHT_FEED(3.0000, 0.0000, -1.0000, 0.0000, 0.0000, 0.0000)
N..... STRAIGHT_TRAVERSE(3.0000, 0.0000, 0.2500, 0.0000, 0.0000, 0.0000)
N..... SET_MOTION_CONTROL_MODE(CANON_CONTINUOUS, 0.000000)
N..... SET_G5X_OFFSET(1, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000)
N..... SET_XY_ROTATION(0.0000)
N..... SET_FEED_MODE(0)
N..... SET_FEED_RATE(0.0000)
N..... STOP_SPINDLE_TURNING()
N..... SET_SPINDLE_MODE(0.0000)
N..... PALLET_SHUTTLE()
N..... PROGRAM_END()

View file

@ -0,0 +1,13 @@
%
( A simple O sub example )
F40
G90 G0 X0 Y0 Z0.25
M98 P1 L3
M30
O1
G91 G0 X1 ; Jog 1" along X (relative)
G90 G99 G81 Z-1.0 R0.25 ; Drill to Z-1.0
M99
%

View file

@ -0,0 +1,3 @@
#!/bin/bash
rs274 -g test.ngc | awk '{$1=""; print}'
exit ${PIPESTATUS[0]}

View file

@ -0,0 +1,22 @@
N..... USE_LENGTH_UNITS(CANON_UNITS_MM)
N..... SET_G5X_OFFSET(1, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000)
N..... SET_G92_OFFSET(0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000)
N..... SET_XY_ROTATION(0.0000)
N..... SET_FEED_REFERENCE(CANON_XYZ)
N..... COMMENT("Fanuc params have global scope; rs274ngc params #1..#30 have local scope ")
MAIN/FANUC: PRE-M98: 1=42.010000; 30=42.300000; 31=42.310000
O1: START: 1=42.010000; 30=42.300000; 31=42.310000
O1: END: 1=13.010000; 30=13.300000; 31=13.310000
MAIN/FANUC: POST-M98: 1=13.010000; 30=13.300000; 31=13.310000
MAIN/RS274NGC: PRE-O-CALL: 1=42.010000; 30=42.300000; 31=42.310000
O2: START: 1=0.000000; 30=0.000000; 31=42.310000
O2: END: 1=13.010000; 30=13.300000; 31=13.310000
MAIN/RS274NGC: POST-O-CALL: 1=42.010000; 30=42.300000; 31=13.310000
N..... SET_G5X_OFFSET(1, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000)
N..... SET_XY_ROTATION(0.0000)
N..... SET_FEED_MODE(0)
N..... SET_FEED_RATE(0.0000)
N..... STOP_SPINDLE_TURNING()
N..... SET_SPINDLE_MODE(0.0000)
N..... PALLET_SHUTTLE()
N..... PROGRAM_END()

View file

@ -0,0 +1,37 @@
%
( Fanuc params have global scope; rs274ngc params #1..#30 have local scope )
; Fanuc-style: Test that all params are globally changed
#1 = 42.01
#30 = 42.30
#31 = 42.31
(PRINT,Q MAIN/FANUC: PRE-M98: 1=#1; 30=#30; 31=#31)
M98 P1
(PRINT,Q MAIN/FANUC: POST-M98: 1=#1; 30=#30; 31=#31)
; RS274NGC-style: Test that params #1..#30 are not globally changed
#1 = 42.01
#30 = 42.30
#31 = 42.31
(PRINT,Q MAIN/RS274NGC: PRE-O-CALL: 1=#1; 30=#30; 31=#31)
O2 call
(PRINT,Q MAIN/RS274NGC: POST-O-CALL: 1=#1; 30=#30; 31=#31)
M30
O1 ; Fanuc-style
(PRINT,Q O1: START: 1=#1; 30=#30; 31=#31)
#1 = 13.01
#30 = 13.30
#31 = 13.31
(PRINT,Q O1: END: 1=#1; 30=#30; 31=#31)
M99
O2 sub ; rs274ngc-style
(PRINT,Q O2: START: 1=#1; 30=#30; 31=#31)
#1 = 13.01
#30 = 13.30
#31 = 13.31
(PRINT,Q O2: END: 1=#1; 30=#30; 31=#31)
O2 endsub
%

View file

@ -0,0 +1,3 @@
#!/bin/bash
rs274 -g test.ngc | awk '{$1=""; print}'
exit ${PIPESTATUS[0]}

View file

@ -0,0 +1,9 @@
executing
Found 'm98' code with no P-word
M98
1 N..... USE_LENGTH_UNITS(CANON_UNITS_MM)
2 N..... SET_G5X_OFFSET(1, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000)
3 N..... SET_G92_OFFSET(0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000)
4 N..... SET_XY_ROTATION(0.0000)
5 N..... SET_FEED_REFERENCE(CANON_XYZ)
6 N..... COMMENT("Fanuc M98 requires P-word ")

View file

@ -0,0 +1,9 @@
%
( Fanuc M98 requires P-word )
M98
O1
#1 = 13
M99
%

View file

@ -0,0 +1,9 @@
#!/bin/bash
rs274 -g test.ngc 2>&1
# expected to fail
if [ $? -ne 0 ]; then
exit 0
fi
exit 1

View file

@ -0,0 +1,7 @@
1 N..... USE_LENGTH_UNITS(CANON_UNITS_MM)
2 N..... SET_G5X_OFFSET(1, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000)
3 N..... SET_G92_OFFSET(0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000)
4 N..... SET_XY_ROTATION(0.0000)
5 N..... SET_FEED_REFERENCE(CANON_XYZ)
6 N..... COMMENT("M98 call non-existant sub ")
7 N..... FINISH()

View file

@ -0,0 +1,6 @@
%
( M98 call non-existant sub )
M98 P1
M30
%

View file

@ -0,0 +1,2 @@
#!/bin/bash -e
! rs274 -g test.ngc

View file

@ -0,0 +1,120 @@
N..... USE_LENGTH_UNITS(CANON_UNITS_MM)
N..... SET_G5X_OFFSET(1, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000)
N..... SET_G92_OFFSET(0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000)
N..... SET_XY_ROTATION(0.0000)
N..... SET_FEED_REFERENCE(CANON_XYZ)
N..... COMMENT("A simple O sub example ")
N..... SET_FEED_RATE(40.0000)
N..... STRAIGHT_TRAVERSE(0.0000, 0.0000, 0.2500, 0.0000, 0.0000, 0.0000)
N..... COMMENT("interpreter: distance mode changed to incremental")
N..... COMMENT("interpreter: retract mode set to r_plane")
N..... STRAIGHT_TRAVERSE(0.0000, 0.0000, 0.5000, 0.0000, 0.0000, 0.0000)
N..... SET_MOTION_CONTROL_MODE(CANON_EXACT_PATH)
N..... STRAIGHT_TRAVERSE(1.0000, 0.0000, 0.5000, 0.0000, 0.0000, 0.0000)
N..... STRAIGHT_FEED(1.0000, 0.0000, -0.5000, 0.0000, 0.0000, 0.0000)
N..... STRAIGHT_TRAVERSE(1.0000, 0.0000, 0.5000, 0.0000, 0.0000, 0.0000)
N..... SET_MOTION_CONTROL_MODE(CANON_CONTINUOUS, 0.000000)
SUB O1 PARAM1 = 1.000000
N..... COMMENT("interpreter: retract mode set to r_plane")
N..... STRAIGHT_TRAVERSE(1.0000, 0.0000, 0.5000, 0.0000, 0.0000, 0.0000)
N..... SET_MOTION_CONTROL_MODE(CANON_EXACT_PATH)
N..... STRAIGHT_TRAVERSE(2.0000, 0.0000, 0.5000, 0.0000, 0.0000, 0.0000)
N..... STRAIGHT_FEED(2.0000, 0.0000, -0.5000, 0.0000, 0.0000, 0.0000)
N..... STRAIGHT_TRAVERSE(2.0000, 0.0000, 0.5000, 0.0000, 0.0000, 0.0000)
N..... SET_MOTION_CONTROL_MODE(CANON_CONTINUOUS, 0.000000)
SUB O1 PARAM1 = 2.000000
N..... COMMENT("interpreter: retract mode set to r_plane")
N..... STRAIGHT_TRAVERSE(2.0000, 0.0000, 0.5000, 0.0000, 0.0000, 0.0000)
N..... SET_MOTION_CONTROL_MODE(CANON_EXACT_PATH)
N..... STRAIGHT_TRAVERSE(3.0000, 0.0000, 0.5000, 0.0000, 0.0000, 0.0000)
N..... STRAIGHT_FEED(3.0000, 0.0000, -0.5000, 0.0000, 0.0000, 0.0000)
N..... STRAIGHT_TRAVERSE(3.0000, 0.0000, 0.5000, 0.0000, 0.0000, 0.0000)
N..... SET_MOTION_CONTROL_MODE(CANON_CONTINUOUS, 0.000000)
SUB O1 PARAM1 = 3.000000
N..... COMMENT("interpreter: retract mode set to r_plane")
N..... STRAIGHT_TRAVERSE(3.0000, 0.0000, 0.5000, 0.0000, 0.0000, 0.0000)
N..... SET_MOTION_CONTROL_MODE(CANON_EXACT_PATH)
N..... STRAIGHT_TRAVERSE(4.0000, 0.0000, 0.5000, 0.0000, 0.0000, 0.0000)
N..... STRAIGHT_FEED(4.0000, 0.0000, -0.5000, 0.0000, 0.0000, 0.0000)
N..... STRAIGHT_TRAVERSE(4.0000, 0.0000, 0.5000, 0.0000, 0.0000, 0.0000)
N..... SET_MOTION_CONTROL_MODE(CANON_CONTINUOUS, 0.000000)
SUB O1 PARAM1 = 4.000000
N..... COMMENT("interpreter: retract mode set to r_plane")
N..... STRAIGHT_TRAVERSE(4.0000, 0.0000, 0.5000, 0.0000, 0.0000, 0.0000)
N..... SET_MOTION_CONTROL_MODE(CANON_EXACT_PATH)
N..... STRAIGHT_TRAVERSE(5.0000, 0.0000, 0.5000, 0.0000, 0.0000, 0.0000)
N..... STRAIGHT_FEED(5.0000, 0.0000, -0.5000, 0.0000, 0.0000, 0.0000)
N..... STRAIGHT_TRAVERSE(5.0000, 0.0000, 0.5000, 0.0000, 0.0000, 0.0000)
N..... SET_MOTION_CONTROL_MODE(CANON_CONTINUOUS, 0.000000)
SUB O1 PARAM1 = 5.000000
N..... COMMENT("interpreter: retract mode set to r_plane")
N..... STRAIGHT_TRAVERSE(5.0000, 0.0000, 0.5000, 0.0000, 0.0000, 0.0000)
N..... SET_MOTION_CONTROL_MODE(CANON_EXACT_PATH)
N..... STRAIGHT_TRAVERSE(6.0000, 0.0000, 0.5000, 0.0000, 0.0000, 0.0000)
N..... STRAIGHT_FEED(6.0000, 0.0000, -0.5000, 0.0000, 0.0000, 0.0000)
N..... STRAIGHT_TRAVERSE(6.0000, 0.0000, 0.5000, 0.0000, 0.0000, 0.0000)
N..... SET_MOTION_CONTROL_MODE(CANON_CONTINUOUS, 0.000000)
SUB O1 PARAM1 = 6.000000
N..... COMMENT("interpreter: retract mode set to r_plane")
N..... STRAIGHT_TRAVERSE(6.0000, 0.0000, 0.5000, 0.0000, 0.0000, 0.0000)
N..... SET_MOTION_CONTROL_MODE(CANON_EXACT_PATH)
N..... STRAIGHT_TRAVERSE(7.0000, 0.0000, 0.5000, 0.0000, 0.0000, 0.0000)
N..... STRAIGHT_FEED(7.0000, 0.0000, -0.5000, 0.0000, 0.0000, 0.0000)
N..... STRAIGHT_TRAVERSE(7.0000, 0.0000, 0.5000, 0.0000, 0.0000, 0.0000)
N..... SET_MOTION_CONTROL_MODE(CANON_CONTINUOUS, 0.000000)
SUB O1 PARAM1 = 7.000000
N..... COMMENT("interpreter: retract mode set to r_plane")
N..... STRAIGHT_TRAVERSE(7.0000, 0.0000, 0.5000, 0.0000, 0.0000, 0.0000)
N..... SET_MOTION_CONTROL_MODE(CANON_EXACT_PATH)
N..... STRAIGHT_TRAVERSE(8.0000, 0.0000, 0.5000, 0.0000, 0.0000, 0.0000)
N..... STRAIGHT_FEED(8.0000, 0.0000, -0.5000, 0.0000, 0.0000, 0.0000)
N..... STRAIGHT_TRAVERSE(8.0000, 0.0000, 0.5000, 0.0000, 0.0000, 0.0000)
N..... SET_MOTION_CONTROL_MODE(CANON_CONTINUOUS, 0.000000)
SUB O1 PARAM1 = 8.000000
N..... COMMENT("interpreter: retract mode set to r_plane")
N..... STRAIGHT_TRAVERSE(8.0000, 0.0000, 0.5000, 0.0000, 0.0000, 0.0000)
N..... SET_MOTION_CONTROL_MODE(CANON_EXACT_PATH)
N..... STRAIGHT_TRAVERSE(9.0000, 0.0000, 0.5000, 0.0000, 0.0000, 0.0000)
N..... STRAIGHT_FEED(9.0000, 0.0000, -0.5000, 0.0000, 0.0000, 0.0000)
N..... STRAIGHT_TRAVERSE(9.0000, 0.0000, 0.5000, 0.0000, 0.0000, 0.0000)
N..... SET_MOTION_CONTROL_MODE(CANON_CONTINUOUS, 0.000000)
SUB O1 PARAM1 = 9.000000
N..... COMMENT("interpreter: retract mode set to r_plane")
N..... STRAIGHT_TRAVERSE(9.0000, 0.0000, 0.5000, 0.0000, 0.0000, 0.0000)
N..... SET_MOTION_CONTROL_MODE(CANON_EXACT_PATH)
N..... STRAIGHT_TRAVERSE(10.0000, 0.0000, 0.5000, 0.0000, 0.0000, 0.0000)
N..... STRAIGHT_FEED(10.0000, 0.0000, -0.5000, 0.0000, 0.0000, 0.0000)
N..... STRAIGHT_TRAVERSE(10.0000, 0.0000, 0.5000, 0.0000, 0.0000, 0.0000)
N..... SET_MOTION_CONTROL_MODE(CANON_CONTINUOUS, 0.000000)
SUB O1 PARAM1 = 10.000000
MAIN 10LOOP PARAM1 = 10.000000
N..... COMMENT("interpreter: distance mode changed to absolute")
N..... STRAIGHT_TRAVERSE(0.0000, 0.0000, 0.2500, 0.0000, 0.0000, 0.0000)
MAIN 0LOOP PARAM1 = 0.000000
N..... STRAIGHT_TRAVERSE(0.0000, 0.0000, 0.2500, 0.0000, 0.0000, 0.0000)
N..... COMMENT("interpreter: distance mode changed to incremental")
N..... COMMENT("interpreter: retract mode set to r_plane")
N..... STRAIGHT_TRAVERSE(0.0000, 0.0000, 0.5000, 0.0000, 0.0000, 0.0000)
N..... SET_MOTION_CONTROL_MODE(CANON_EXACT_PATH)
N..... STRAIGHT_TRAVERSE(1.0000, 0.0000, 0.5000, 0.0000, 0.0000, 0.0000)
N..... STRAIGHT_FEED(1.0000, 0.0000, -0.5000, 0.0000, 0.0000, 0.0000)
N..... STRAIGHT_TRAVERSE(1.0000, 0.0000, 0.5000, 0.0000, 0.0000, 0.0000)
N..... SET_MOTION_CONTROL_MODE(CANON_CONTINUOUS, 0.000000)
SUB O1 PARAM1 = 1.000000
N..... COMMENT("interpreter: retract mode set to r_plane")
N..... STRAIGHT_TRAVERSE(1.0000, 0.0000, 0.5000, 0.0000, 0.0000, 0.0000)
N..... SET_MOTION_CONTROL_MODE(CANON_EXACT_PATH)
N..... STRAIGHT_TRAVERSE(2.0000, 0.0000, 0.5000, 0.0000, 0.0000, 0.0000)
N..... STRAIGHT_FEED(2.0000, 0.0000, -0.5000, 0.0000, 0.0000, 0.0000)
N..... STRAIGHT_TRAVERSE(2.0000, 0.0000, 0.5000, 0.0000, 0.0000, 0.0000)
N..... SET_MOTION_CONTROL_MODE(CANON_CONTINUOUS, 0.000000)
SUB O1 PARAM1 = 2.000000
MAIN 2LOOP PARAM1 = 2.000000
N..... SET_G5X_OFFSET(1, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000)
N..... SET_XY_ROTATION(0.0000)
N..... SET_FEED_MODE(0)
N..... SET_FEED_RATE(0.0000)
N..... STOP_SPINDLE_TURNING()
N..... SET_SPINDLE_MODE(0.0000)
N..... PALLET_SHUTTLE()
N..... PROGRAM_END()

View file

@ -0,0 +1,27 @@
%
( A simple O sub example )
F40
; Test with 10 loops
#1 = 0
G90 G0 X0 Y0 Z0.25
M98 P1 L10
(PRINT,X MAIN 10LOOP PARAM1 = #1)
; Test with 0 loops
#1 = 0
G90 G0 X0 Y0 Z0.25
M98 P1 L0
(PRINT,X MAIN 0LOOP PARAM1 = #1)
; Test with 2 loops
#1 = 0
G90 G0 X0 Y0 Z0.25
M98 P1 L2
(PRINT,X MAIN 2LOOP PARAM1 = #1)
M30
O1
G91 G99 G81 X1 Z-1.0 R0.25 ; Drill to Z-1.0
#1 = [#1 + 1]
(PRINT,X SUB O1 PARAM1 = #1)
M99
%

View file

@ -0,0 +1,3 @@
#!/bin/bash
rs274 -g test.ngc | awk '{$1=""; print}'
exit ${PIPESTATUS[0]}

View file

@ -0,0 +1,9 @@
%
( Fanuc 'O...' sub must be called with M98 )
O1 call
O1
(PRINT,X FANUC)
M99
%

View file

@ -0,0 +1,9 @@
%
( Fanuc 'O...' sub must end with M99 )
M98 P1
O1
(PRINT,X FANUC)
O1 endsub
%

View file

@ -0,0 +1,9 @@
%
( RS274NGC 'O...' sub must not be called with M98 )
M98 P1
O1 sub
(PRINT,X FANUC)
O1 endsub
%

View file

@ -0,0 +1,9 @@
%
( RS274NGC 'O... sub' sub must not end with M99 )
O1 call
O1 sub
(PRINT,X FANUC)
M99
%

View file

@ -0,0 +1,38 @@
executing
Fanuc 'O....' subroutine must be called with 'M98'
O1
1 N..... USE_LENGTH_UNITS(CANON_UNITS_MM)
2 N..... SET_G5X_OFFSET(1, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000)
3 N..... SET_G92_OFFSET(0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000)
4 N..... SET_XY_ROTATION(0.0000)
5 N..... SET_FEED_REFERENCE(CANON_XYZ)
6 N..... COMMENT("Fanuc 'O...' sub must be called with M98 ")
executing
1 N..... USE_LENGTH_UNITS(CANON_UNITS_MM)
2 N..... SET_G5X_OFFSET(1, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000)
3 N..... SET_G92_OFFSET(0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000)
4 N..... SET_XY_ROTATION(0.0000)
5 N..... SET_FEED_REFERENCE(CANON_XYZ)
6 N..... COMMENT("Fanuc 'O...' sub must end with M99 ")
X FANUC
Fanuc 'O....' subroutine definition must end with 'M99'
O1 endsub
executing
'O.... sub' subroutine must be called with 'O.... call'
O1 sub
1 N..... USE_LENGTH_UNITS(CANON_UNITS_MM)
2 N..... SET_G5X_OFFSET(1, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000)
3 N..... SET_G92_OFFSET(0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000)
4 N..... SET_XY_ROTATION(0.0000)
5 N..... SET_FEED_REFERENCE(CANON_XYZ)
6 N..... COMMENT("RS274NGC 'O...' sub must not be called with M98 ")
executing
1 N..... USE_LENGTH_UNITS(CANON_UNITS_MM)
2 N..... SET_G5X_OFFSET(1, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000)
3 N..... SET_G92_OFFSET(0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000)
4 N..... SET_XY_ROTATION(0.0000)
5 N..... SET_FEED_REFERENCE(CANON_XYZ)
6 N..... COMMENT("RS274NGC 'O... sub' sub must not end with M99 ")
X FANUC
'O.... endsub' or 'O.... return' must follow 'O.... sub' subroutine definition
M99

View file

@ -0,0 +1,10 @@
#!/bin/bash
# All expected to fail
# Fanuc 'O...' sub definition mixed with RS274NGC 'O... endsub'/'O... call'
! rs274 -g O...-called-with-O..._call.ngc 2>&1 || exit 1
! rs274 -g O...-ended-with-O..._endsub.ngc 2>&1 || exit 1
# RS274 'O... sub' sub definition mixed with Fanuc 'M99'/'M98'
! rs274 -g O...-sub-called-with-M98.ngc 2>&1 || exit 1
! rs274 -g O...-sub-ended-with-M99.ngc 2>&1 || exit 1

View file

@ -0,0 +1,46 @@
N..... USE_LENGTH_UNITS(CANON_UNITS_MM)
N..... SET_G5X_OFFSET(1, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000)
N..... SET_G92_OFFSET(0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000)
N..... SET_XY_ROTATION(0.0000)
N..... SET_FEED_REFERENCE(CANON_XYZ)
N..... COMMENT("A nested Fanuc subroutine example ")
MAIN BEGIN: 1=0.000000
>>>> LOOP [O2.O1]: 0.100000
>>>> LOOP [O2.O1]: 0.200000
>>>> LOOP [O2.O1]: 0.300000
>>>> LOOP [O2.O1]: 0.400000
>>>> LOOP [O2.O1]: 0.500000
O2 END: 1=1.000000
>>>> LOOP [O2.O1]: 1.100000
>>>> LOOP [O2.O1]: 1.200000
>>>> LOOP [O2.O1]: 1.300000
>>>> LOOP [O2.O1]: 1.400000
>>>> LOOP [O2.O1]: 1.500000
O2 END: 1=2.000000
>>>> LOOP [O2.O1]: 2.100000
>>>> LOOP [O2.O1]: 2.200000
>>>> LOOP [O2.O1]: 2.300000
>>>> LOOP [O2.O1]: 2.400000
>>>> LOOP [O2.O1]: 2.500000
O2 END: 1=3.000000
>>>> LOOP [O2.O1]: 3.100000
>>>> LOOP [O2.O1]: 3.200000
>>>> LOOP [O2.O1]: 3.300000
>>>> LOOP [O2.O1]: 3.400000
>>>> LOOP [O2.O1]: 3.500000
O2 END: 1=4.000000
>>>> LOOP [O2.O1]: 4.100000
>>>> LOOP [O2.O1]: 4.200000
>>>> LOOP [O2.O1]: 4.300000
>>>> LOOP [O2.O1]: 4.400000
>>>> LOOP [O2.O1]: 4.500000
O2 END: 1=5.000000
MAIN END: 1=5.000000
N..... SET_G5X_OFFSET(1, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000)
N..... SET_XY_ROTATION(0.0000)
N..... SET_FEED_MODE(0)
N..... SET_FEED_RATE(0.0000)
N..... STOP_SPINDLE_TURNING()
N..... SET_SPINDLE_MODE(0.0000)
N..... PALLET_SHUTTLE()
N..... PROGRAM_END()

View file

@ -0,0 +1,20 @@
%
( A nested Fanuc subroutine example )
#1 = 0
(PRINT,X MAIN BEGIN: 1=#1)
M98 P2 L5
(PRINT,X MAIN END: 1=#1)
M30
O2
M98 P1 L5
#1 = [FIX[#1] + 1]
(PRINT,X O2 END: 1=#1)
M99
O1
#1 = [#1 + 0.1]
(PRINT,X >>>> LOOP [O2.O1]: #1)
M99
%

View file

@ -0,0 +1,3 @@
#!/bin/bash
rs274 -g test.ngc | awk '{$1=""; print}'
exit ${PIPESTATUS[0]}

View file

@ -0,0 +1,15 @@
N..... USE_LENGTH_UNITS(CANON_UNITS_MM)
N..... SET_G5X_OFFSET(1, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000)
N..... SET_G92_OFFSET(0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000)
N..... SET_XY_ROTATION(0.0000)
N..... SET_FEED_REFERENCE(CANON_XYZ)
N..... COMMENT("Fanuc-style subs may follow main program ")
IN O1
N..... SET_G5X_OFFSET(1, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000)
N..... SET_XY_ROTATION(0.0000)
N..... SET_FEED_MODE(0)
N..... SET_FEED_RATE(0.0000)
N..... STOP_SPINDLE_TURNING()
N..... SET_SPINDLE_MODE(0.0000)
N..... PALLET_SHUTTLE()
N..... PROGRAM_END()

View file

@ -0,0 +1,10 @@
%
( Fanuc-style subs may follow main program )
M98 P1
M30
O1
(PRINT,X IN O1)
M99
%

View file

@ -0,0 +1,3 @@
#!/bin/bash
rs274 -g test.ngc | awk '{$1=""; print}'
exit ${PIPESTATUS[0]}

View file

@ -0,0 +1,183 @@
program: fanuc; ini: fanuc
executing
N..... USE_LENGTH_UNITS(CANON_UNITS_MM)
N..... SET_G5X_OFFSET(1, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000)
N..... SET_G92_OFFSET(0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000)
N..... SET_XY_ROTATION(0.0000)
N..... SET_FEED_REFERENCE(CANON_XYZ)
N..... COMMENT("A simple O sub example ")
N..... SET_FEED_RATE(40.0000)
N..... STRAIGHT_TRAVERSE(0.0000, 0.0000, 0.2500, 0.0000, 0.0000, 0.0000)
N..... COMMENT("interpreter: distance mode changed to incremental")
N..... STRAIGHT_TRAVERSE(1.0000, 0.0000, 0.2500, 0.0000, 0.0000, 0.0000)
N..... COMMENT("interpreter: distance mode changed to absolute")
N..... COMMENT("interpreter: retract mode set to r_plane")
N..... SET_MOTION_CONTROL_MODE(CANON_EXACT_PATH)
N..... STRAIGHT_TRAVERSE(1.0000, 0.0000, 0.2500, 0.0000, 0.0000, 0.0000)
N..... STRAIGHT_FEED(1.0000, 0.0000, -1.0000, 0.0000, 0.0000, 0.0000)
N..... STRAIGHT_TRAVERSE(1.0000, 0.0000, 0.2500, 0.0000, 0.0000, 0.0000)
N..... SET_MOTION_CONTROL_MODE(CANON_CONTINUOUS, 0.000000)
N..... COMMENT("interpreter: distance mode changed to incremental")
N..... STRAIGHT_TRAVERSE(2.0000, 0.0000, 0.2500, 0.0000, 0.0000, 0.0000)
N..... COMMENT("interpreter: distance mode changed to absolute")
N..... COMMENT("interpreter: retract mode set to r_plane")
N..... SET_MOTION_CONTROL_MODE(CANON_EXACT_PATH)
N..... STRAIGHT_TRAVERSE(2.0000, 0.0000, 0.2500, 0.0000, 0.0000, 0.0000)
N..... STRAIGHT_FEED(2.0000, 0.0000, -1.0000, 0.0000, 0.0000, 0.0000)
N..... STRAIGHT_TRAVERSE(2.0000, 0.0000, 0.2500, 0.0000, 0.0000, 0.0000)
N..... SET_MOTION_CONTROL_MODE(CANON_CONTINUOUS, 0.000000)
N..... COMMENT("interpreter: distance mode changed to incremental")
N..... STRAIGHT_TRAVERSE(3.0000, 0.0000, 0.2500, 0.0000, 0.0000, 0.0000)
N..... COMMENT("interpreter: distance mode changed to absolute")
N..... COMMENT("interpreter: retract mode set to r_plane")
N..... SET_MOTION_CONTROL_MODE(CANON_EXACT_PATH)
N..... STRAIGHT_TRAVERSE(3.0000, 0.0000, 0.2500, 0.0000, 0.0000, 0.0000)
N..... STRAIGHT_FEED(3.0000, 0.0000, -1.0000, 0.0000, 0.0000, 0.0000)
N..... STRAIGHT_TRAVERSE(3.0000, 0.0000, 0.2500, 0.0000, 0.0000, 0.0000)
N..... SET_MOTION_CONTROL_MODE(CANON_CONTINUOUS, 0.000000)
N..... SET_G5X_OFFSET(1, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000)
N..... SET_XY_ROTATION(0.0000)
N..... SET_FEED_MODE(0)
N..... SET_FEED_RATE(0.0000)
N..... STOP_SPINDLE_TURNING()
N..... SET_SPINDLE_MODE(0.0000)
N..... PALLET_SHUTTLE()
N..... PROGRAM_END()
program: rs274ngc; ini: fanuc
executing
N..... USE_LENGTH_UNITS(CANON_UNITS_MM)
N..... SET_G5X_OFFSET(1, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000)
N..... SET_G92_OFFSET(0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000)
N..... SET_XY_ROTATION(0.0000)
N..... SET_FEED_REFERENCE(CANON_XYZ)
N..... COMMENT("A simple O sub example ")
N..... SET_FEED_RATE(40.0000)
N..... STRAIGHT_TRAVERSE(0.0000, 0.0000, 0.2500, 0.0000, 0.0000, 0.0000)
N..... COMMENT("interpreter: distance mode changed to incremental")
N..... STRAIGHT_TRAVERSE(1.0000, 0.0000, 0.2500, 0.0000, 0.0000, 0.0000)
N..... COMMENT("interpreter: distance mode changed to absolute")
N..... COMMENT("interpreter: retract mode set to r_plane")
N..... SET_MOTION_CONTROL_MODE(CANON_EXACT_PATH)
N..... STRAIGHT_TRAVERSE(1.0000, 0.0000, 0.2500, 0.0000, 0.0000, 0.0000)
N..... STRAIGHT_FEED(1.0000, 0.0000, -1.0000, 0.0000, 0.0000, 0.0000)
N..... STRAIGHT_TRAVERSE(1.0000, 0.0000, 0.2500, 0.0000, 0.0000, 0.0000)
N..... SET_MOTION_CONTROL_MODE(CANON_CONTINUOUS, 0.000000)
N..... SET_G5X_OFFSET(1, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000)
N..... SET_XY_ROTATION(0.0000)
N..... SET_FEED_MODE(0)
N..... SET_FEED_RATE(0.0000)
N..... STOP_SPINDLE_TURNING()
N..... SET_SPINDLE_MODE(0.0000)
N..... PALLET_SHUTTLE()
N..... PROGRAM_END()
program: fanuc; ini: NO fanuc
executing
DISABLE_FANUC_STYLE_SUB set in .ini file, but found m98
M98 P1 L3
N..... USE_LENGTH_UNITS(CANON_UNITS_MM)
N..... SET_G5X_OFFSET(1, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000)
N..... SET_G92_OFFSET(0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000)
N..... SET_XY_ROTATION(0.0000)
N..... SET_FEED_REFERENCE(CANON_XYZ)
N..... COMMENT("A simple O sub example ")
N..... SET_FEED_RATE(40.0000)
N..... STRAIGHT_TRAVERSE(0.0000, 0.0000, 0.2500, 0.0000, 0.0000, 0.0000)
program: rs274ngc; ini: NO fanuc
executing
N..... USE_LENGTH_UNITS(CANON_UNITS_MM)
N..... SET_G5X_OFFSET(1, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000)
N..... SET_G92_OFFSET(0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000)
N..... SET_XY_ROTATION(0.0000)
N..... SET_FEED_REFERENCE(CANON_XYZ)
N..... COMMENT("A simple O sub example ")
N..... SET_FEED_RATE(40.0000)
N..... STRAIGHT_TRAVERSE(0.0000, 0.0000, 0.2500, 0.0000, 0.0000, 0.0000)
N..... COMMENT("interpreter: distance mode changed to incremental")
N..... STRAIGHT_TRAVERSE(1.0000, 0.0000, 0.2500, 0.0000, 0.0000, 0.0000)
N..... COMMENT("interpreter: distance mode changed to absolute")
N..... COMMENT("interpreter: retract mode set to r_plane")
N..... SET_MOTION_CONTROL_MODE(CANON_EXACT_PATH)
N..... STRAIGHT_TRAVERSE(1.0000, 0.0000, 0.2500, 0.0000, 0.0000, 0.0000)
N..... STRAIGHT_FEED(1.0000, 0.0000, -1.0000, 0.0000, 0.0000, 0.0000)
N..... STRAIGHT_TRAVERSE(1.0000, 0.0000, 0.2500, 0.0000, 0.0000, 0.0000)
N..... SET_MOTION_CONTROL_MODE(CANON_CONTINUOUS, 0.000000)
N..... SET_G5X_OFFSET(1, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000)
N..... SET_XY_ROTATION(0.0000)
N..... SET_FEED_MODE(0)
N..... SET_FEED_RATE(0.0000)
N..... STOP_SPINDLE_TURNING()
N..... SET_SPINDLE_MODE(0.0000)
N..... PALLET_SHUTTLE()
N..... PROGRAM_END()
program: fanuc; ini: (none)
executing
N..... USE_LENGTH_UNITS(CANON_UNITS_MM)
N..... SET_G5X_OFFSET(1, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000)
N..... SET_G92_OFFSET(0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000)
N..... SET_XY_ROTATION(0.0000)
N..... SET_FEED_REFERENCE(CANON_XYZ)
N..... COMMENT("A simple O sub example ")
N..... SET_FEED_RATE(40.0000)
N..... STRAIGHT_TRAVERSE(0.0000, 0.0000, 0.2500, 0.0000, 0.0000, 0.0000)
N..... COMMENT("interpreter: distance mode changed to incremental")
N..... STRAIGHT_TRAVERSE(1.0000, 0.0000, 0.2500, 0.0000, 0.0000, 0.0000)
N..... COMMENT("interpreter: distance mode changed to absolute")
N..... COMMENT("interpreter: retract mode set to r_plane")
N..... SET_MOTION_CONTROL_MODE(CANON_EXACT_PATH)
N..... STRAIGHT_TRAVERSE(1.0000, 0.0000, 0.2500, 0.0000, 0.0000, 0.0000)
N..... STRAIGHT_FEED(1.0000, 0.0000, -1.0000, 0.0000, 0.0000, 0.0000)
N..... STRAIGHT_TRAVERSE(1.0000, 0.0000, 0.2500, 0.0000, 0.0000, 0.0000)
N..... SET_MOTION_CONTROL_MODE(CANON_CONTINUOUS, 0.000000)
N..... COMMENT("interpreter: distance mode changed to incremental")
N..... STRAIGHT_TRAVERSE(2.0000, 0.0000, 0.2500, 0.0000, 0.0000, 0.0000)
N..... COMMENT("interpreter: distance mode changed to absolute")
N..... COMMENT("interpreter: retract mode set to r_plane")
N..... SET_MOTION_CONTROL_MODE(CANON_EXACT_PATH)
N..... STRAIGHT_TRAVERSE(2.0000, 0.0000, 0.2500, 0.0000, 0.0000, 0.0000)
N..... STRAIGHT_FEED(2.0000, 0.0000, -1.0000, 0.0000, 0.0000, 0.0000)
N..... STRAIGHT_TRAVERSE(2.0000, 0.0000, 0.2500, 0.0000, 0.0000, 0.0000)
N..... SET_MOTION_CONTROL_MODE(CANON_CONTINUOUS, 0.000000)
N..... COMMENT("interpreter: distance mode changed to incremental")
N..... STRAIGHT_TRAVERSE(3.0000, 0.0000, 0.2500, 0.0000, 0.0000, 0.0000)
N..... COMMENT("interpreter: distance mode changed to absolute")
N..... COMMENT("interpreter: retract mode set to r_plane")
N..... SET_MOTION_CONTROL_MODE(CANON_EXACT_PATH)
N..... STRAIGHT_TRAVERSE(3.0000, 0.0000, 0.2500, 0.0000, 0.0000, 0.0000)
N..... STRAIGHT_FEED(3.0000, 0.0000, -1.0000, 0.0000, 0.0000, 0.0000)
N..... STRAIGHT_TRAVERSE(3.0000, 0.0000, 0.2500, 0.0000, 0.0000, 0.0000)
N..... SET_MOTION_CONTROL_MODE(CANON_CONTINUOUS, 0.000000)
N..... SET_G5X_OFFSET(1, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000)
N..... SET_XY_ROTATION(0.0000)
N..... SET_FEED_MODE(0)
N..... SET_FEED_RATE(0.0000)
N..... STOP_SPINDLE_TURNING()
N..... SET_SPINDLE_MODE(0.0000)
N..... PALLET_SHUTTLE()
N..... PROGRAM_END()
program: rs274ngc; ini: (none)
executing
N..... USE_LENGTH_UNITS(CANON_UNITS_MM)
N..... SET_G5X_OFFSET(1, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000)
N..... SET_G92_OFFSET(0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000)
N..... SET_XY_ROTATION(0.0000)
N..... SET_FEED_REFERENCE(CANON_XYZ)
N..... COMMENT("A simple O sub example ")
N..... SET_FEED_RATE(40.0000)
N..... STRAIGHT_TRAVERSE(0.0000, 0.0000, 0.2500, 0.0000, 0.0000, 0.0000)
N..... COMMENT("interpreter: distance mode changed to incremental")
N..... STRAIGHT_TRAVERSE(1.0000, 0.0000, 0.2500, 0.0000, 0.0000, 0.0000)
N..... COMMENT("interpreter: distance mode changed to absolute")
N..... COMMENT("interpreter: retract mode set to r_plane")
N..... SET_MOTION_CONTROL_MODE(CANON_EXACT_PATH)
N..... STRAIGHT_TRAVERSE(1.0000, 0.0000, 0.2500, 0.0000, 0.0000, 0.0000)
N..... STRAIGHT_FEED(1.0000, 0.0000, -1.0000, 0.0000, 0.0000, 0.0000)
N..... STRAIGHT_TRAVERSE(1.0000, 0.0000, 0.2500, 0.0000, 0.0000, 0.0000)
N..... SET_MOTION_CONTROL_MODE(CANON_CONTINUOUS, 0.000000)
N..... SET_G5X_OFFSET(1, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000)
N..... SET_XY_ROTATION(0.0000)
N..... SET_FEED_MODE(0)
N..... SET_FEED_RATE(0.0000)
N..... STOP_SPINDLE_TURNING()
N..... SET_SPINDLE_MODE(0.0000)
N..... PALLET_SHUTTLE()
N..... PROGRAM_END()

View file

@ -0,0 +1,2 @@
[RS274NGC]
DISABLE_FANUC_STYLE_SUB = 0

View file

@ -0,0 +1,13 @@
%
( A simple O sub example )
F40
G90 G0 X0 Y0 Z0.25
M98 P1 L3
M30
O1
G91 G0 X1 ; Jog 1" along X (relative)
G90 G99 G81 Z-1.0 R0.25 ; Drill to Z-1.0
M99
%

View file

@ -0,0 +1,4 @@
[RS274NGC]
DISABLE_FANUC_STYLE_SUB = 1
[EMC]
DEBUG = 2147483647

View file

@ -0,0 +1,13 @@
%
( A simple O sub example )
O1 sub
G91 G0 X1 ; Jog 1" along X (relative)
G90 G99 G81 Z-1.0 R0.25 ; Drill to Z-1.0
O1 endsub
F40
G90 G0 X0 Y0 Z0.25
O1 call
M30
%

View file

@ -0,0 +1,27 @@
#!/bin/bash
trim() { sed 's/^ *[0-9][0-9]* //'; }
# Fanuc enabled:
# - with Fanuc sub: pass
echo "program: fanuc; ini: fanuc"
rs274 -g -i test-fanuc.ini test-fanuc.ngc 2>&1 | trim
# - with rs274ngc sub: pass (rs274ngc subs not disabled)
echo "program: rs274ngc; ini: fanuc"
rs274 -g -i test-fanuc.ini test-rs274ngc.ngc 2>&1 | trim
# Fanuc disabled:
# - with Fanuc sub: fail
echo "program: fanuc; ini: NO fanuc"
{ ! rs274 -g -i test-no-fanuc.ini test-fanuc.ngc 2>&1; } | trim || exit 1
# - with rs274ngc sub: pass
echo "program: rs274ngc; ini: NO fanuc"
rs274 -g -i test-no-fanuc.ini test-rs274ngc.ngc 2>&1 | trim
# Default (Fanuc enabled):
# - with Fanuc sub: pass
echo "program: fanuc; ini: (none)"
rs274 -g test-fanuc.ngc 2>&1 | trim
# - with rs274ngc sub: pass (rs274ngc subs not disabled)
echo "program: rs274ngc; ini: (none)"
rs274 -g test-rs274ngc.ngc 2>&1 | trim

View file

@ -0,0 +1,16 @@
N..... USE_LENGTH_UNITS(CANON_UNITS_MM)
N..... SET_G5X_OFFSET(1, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000)
N..... SET_G92_OFFSET(0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000)
N..... SET_XY_ROTATION(0.0000)
N..... SET_FEED_REFERENCE(CANON_XYZ)
N..... COMMENT("main program")
got here
N..... COMMENT("end")
N..... SET_G5X_OFFSET(1, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000)
N..... SET_XY_ROTATION(0.0000)
N..... SET_FEED_MODE(0)
N..... SET_FEED_RATE(0.0000)
N..... STOP_SPINDLE_TURNING()
N..... SET_SPINDLE_MODE(0.0000)
N..... PALLET_SHUTTLE()
N..... PROGRAM_END()

View file

@ -0,0 +1,14 @@
%
(main program)
M98 P0002
M30 (end)
O0002 (O-word begins with '0')
(PRINT,x got here)
M99
O2 (O-word does not begin with '0')
(PRINT,x ERROR: should not get here)
M99
%

View file

@ -0,0 +1,3 @@
#!/bin/bash
rs274 -g test.ngc | awk '{$1=""; print}'
exit ${PIPESTATUS[0]}

View file

@ -0,0 +1,124 @@
Legal test end-main-with-m2:
N..... USE_LENGTH_UNITS(CANON_UNITS_MM)
N..... SET_G5X_OFFSET(1, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000)
N..... SET_G92_OFFSET(0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000)
N..... SET_XY_ROTATION(0.0000)
N..... SET_FEED_REFERENCE(CANON_XYZ)
N..... COMMENT("legal example")
N..... COMMENT("Main program defined with numeric O-word title, terminated by M2")
N..... STRAIGHT_TRAVERSE(1.0000, 2.0000, 0.0000, 0.0000, 0.0000, 0.0000)
N..... COMMENT("calling sub 2")
N..... COMMENT("in sub 2")
N..... STRAIGHT_TRAVERSE(1.0000, 2.0000, 3.0000, 0.0000, 0.0000, 0.0000)
N..... COMMENT("returning from sub 2")
N..... COMMENT("returned from sub 2")
N..... COMMENT("end of main")
N..... SET_G5X_OFFSET(1, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000)
N..... SET_XY_ROTATION(0.0000)
N..... SET_FEED_MODE(0)
N..... SET_FEED_RATE(0.0000)
N..... STOP_SPINDLE_TURNING()
N..... SET_SPINDLE_MODE(0.0000)
N..... PROGRAM_END()
Legal test end-main-with-m02:
N..... USE_LENGTH_UNITS(CANON_UNITS_MM)
N..... SET_G5X_OFFSET(1, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000)
N..... SET_G92_OFFSET(0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000)
N..... SET_XY_ROTATION(0.0000)
N..... SET_FEED_REFERENCE(CANON_XYZ)
N..... COMMENT("legal example")
N..... COMMENT("Main program defined with numeric O-word title, terminated by M02")
N..... STRAIGHT_TRAVERSE(1.0000, 2.0000, 0.0000, 0.0000, 0.0000, 0.0000)
N..... COMMENT("calling sub 2")
N..... COMMENT("in sub 2")
N..... STRAIGHT_TRAVERSE(1.0000, 2.0000, 3.0000, 0.0000, 0.0000, 0.0000)
N..... COMMENT("returning from sub 2")
N..... COMMENT("returned from sub 2")
N..... COMMENT("end of main")
N..... SET_G5X_OFFSET(1, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000)
N..... SET_XY_ROTATION(0.0000)
N..... SET_FEED_MODE(0)
N..... SET_FEED_RATE(0.0000)
N..... STOP_SPINDLE_TURNING()
N..... SET_SPINDLE_MODE(0.0000)
N..... PROGRAM_END()
Legal test end-main-with-m30:
N..... USE_LENGTH_UNITS(CANON_UNITS_MM)
N..... SET_G5X_OFFSET(1, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000)
N..... SET_G92_OFFSET(0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000)
N..... SET_XY_ROTATION(0.0000)
N..... SET_FEED_REFERENCE(CANON_XYZ)
N..... COMMENT("legal example")
N..... COMMENT("Main program defined with numeric O-word title, terminated by M30")
N..... STRAIGHT_TRAVERSE(1.0000, 2.0000, 0.0000, 0.0000, 0.0000, 0.0000)
N..... COMMENT("calling sub 2")
N..... COMMENT("in sub 2")
N..... STRAIGHT_TRAVERSE(1.0000, 2.0000, 3.0000, 0.0000, 0.0000, 0.0000)
N..... COMMENT("returning from sub 2")
N..... COMMENT("returned from sub 2")
N..... COMMENT("end of main")
N..... SET_G5X_OFFSET(1, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000)
N..... SET_XY_ROTATION(0.0000)
N..... SET_FEED_MODE(0)
N..... SET_FEED_RATE(0.0000)
N..... STOP_SPINDLE_TURNING()
N..... SET_SPINDLE_MODE(0.0000)
N..... PALLET_SHUTTLE()
N..... PROGRAM_END()
Legal test end-main-with-percent:
N..... USE_LENGTH_UNITS(CANON_UNITS_MM)
N..... SET_G5X_OFFSET(1, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000)
N..... SET_G92_OFFSET(0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000)
N..... SET_XY_ROTATION(0.0000)
N..... SET_FEED_REFERENCE(CANON_XYZ)
N..... COMMENT("legal example")
N..... COMMENT("Main program defined with numeric O-word title, terminated by percent")
N..... STRAIGHT_TRAVERSE(1.0000, 2.0000, 0.0000, 0.0000, 0.0000, 0.0000)
N..... COMMENT("calling sub 2")
N..... COMMENT("in sub 2")
N..... STRAIGHT_TRAVERSE(1.0000, 2.0000, 3.0000, 0.0000, 0.0000, 0.0000)
N..... COMMENT("returning from sub 2")
N..... COMMENT("returned from sub 2")
N..... COMMENT("end of main signaled by percent")
N..... FINISH()
Illegal test end-main-with-eof:
N..... USE_LENGTH_UNITS(CANON_UNITS_MM)
N..... SET_G5X_OFFSET(1, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000)
N..... SET_G92_OFFSET(0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000)
N..... SET_XY_ROTATION(0.0000)
N..... SET_FEED_REFERENCE(CANON_XYZ)
N..... COMMENT("legal example")
N..... COMMENT("Main program defined with numeric O-word title, terminated by EOF")
N..... STRAIGHT_TRAVERSE(1.0000, 2.0000, 0.0000, 0.0000, 0.0000, 0.0000)
N..... COMMENT("calling sub 2")
N..... COMMENT("in sub 2")
N..... STRAIGHT_TRAVERSE(1.0000, 2.0000, 3.0000, 0.0000, 0.0000, 0.0000)
N..... COMMENT("returning from sub 2")
N..... COMMENT("returned from sub 2")
N..... COMMENT("end of main signaled by EOF")
Illegal test no-m30-before-osub:
N..... USE_LENGTH_UNITS(CANON_UNITS_MM)
N..... SET_G5X_OFFSET(1, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000)
N..... SET_G92_OFFSET(0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000)
N..... SET_XY_ROTATION(0.0000)
N..... SET_FEED_REFERENCE(CANON_XYZ)
N..... COMMENT("illegal example")
N..... COMMENT("Define rs274-style sub before numeric O-word main program end")
N..... STRAIGHT_TRAVERSE(1.0000, 2.0000, 0.0000, 0.0000, 0.0000, 0.0000)
N..... COMMENT("calling sub 2")
N..... COMMENT("in sub 2")
N..... STRAIGHT_TRAVERSE(1.0000, 2.0000, 3.0000, 0.0000, 0.0000, 0.0000)
N..... COMMENT("returning from sub 2")
N..... COMMENT("returned from sub 2")
N..... COMMENT("Illegal: O-sub with no M02 or M30 terminating main")
Illegal test sub-after-percent:
N..... USE_LENGTH_UNITS(CANON_UNITS_MM)
N..... SET_G5X_OFFSET(1, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000)
N..... SET_G92_OFFSET(0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000)
N..... SET_XY_ROTATION(0.0000)
N..... SET_FEED_REFERENCE(CANON_XYZ)
N..... COMMENT("illegal example")
N..... COMMENT("Define sub after percent [= after EOF]")
N..... STRAIGHT_TRAVERSE(1.0000, 2.0000, 0.0000, 0.0000, 0.0000, 0.0000)
N..... COMMENT("calling sub 2")
N..... FINISH()

View file

@ -0,0 +1,15 @@
(legal example)
(Main program defined with numeric O-word title, terminated by EOF)
O2 sub (subprogram begin) (program end signaled by O2 sub)
(in sub 2)
G0 Z3
(returning from sub 2)
O2 endsub
O1 (main program begin)
G0 X1Y2
(calling sub 2)
O2 call
(returned from sub 2)
(end of main signaled by EOF)

View file

@ -0,0 +1,14 @@
(illegal example)
(Define rs274-style sub before numeric O-word main program end)
O1 (main program begin)
G0 X1Y2
(calling sub 2)
O2 call
(returned from sub 2)
(Illegal: O-sub with no M02 or M30 terminating main)
O2 sub (subprogram begin)
(in sub 2)
G0 Z3
(returning from sub 2)
O2 endsub

View file

@ -0,0 +1,25 @@
%
(illegal example)
(Define sub after percent [= after EOF])
O1 (main program begin)
G0 X1Y2
(calling sub 2)
O2 call
(returned from sub 2)
%
(Nothing should follow % sign)
(From http://linuxcnc.org/docs/html/gcode/overview.html#_overview )
( The useful contents of a file demarcated by percents stop after )
( the second percent line. Anything after that is ignored. )
(From Smid 3rd Ed. p. 62)
( The percent sign (%) after M30 is a special _stop_code_. This )
( symbol terminates the loading of a program from an external )
( device. It is also called the _end-of-file_marker_. )
O2 sub (subprogram begin) (program end signaled by O2 sub)
(in sub 2)
G0 Z3
(returning from sub 2)
O2 endsub

View file

@ -0,0 +1,15 @@
(legal example)
(Main program defined with numeric O-word title, terminated by M02)
O1 (main program begin)
G0 X1Y2
(calling sub 2)
O2 call
(returned from sub 2)
M02 (end of main)
(should never get here)
O2 sub (subprogram begin) (program end signaled by O2 sub)
(in sub 2)
G0 Z3
(returning from sub 2)
O2 endsub

View file

@ -0,0 +1,15 @@
(legal example)
(Main program defined with numeric O-word title, terminated by M2)
O1 (main program begin)
G0 X1Y2
(calling sub 2)
O2 call
(returned from sub 2)
M2 (end of main)
(should never get here)
O2 sub (subprogram begin) (program end signaled by O2 sub)
(in sub 2)
G0 Z3
(returning from sub 2)
O2 endsub

View file

@ -0,0 +1,15 @@
(legal example)
(Main program defined with numeric O-word title, terminated by M30)
O1 (main program begin)
G0 X1Y2
(calling sub 2)
O2 call
(returned from sub 2)
M30 (end of main)
(should never get here)
O2 sub (subprogram begin) (program end signaled by O2 sub)
(in sub 2)
G0 Z3
(returning from sub 2)
O2 endsub

View file

@ -0,0 +1,17 @@
%
(legal example)
(Main program defined with numeric O-word title, terminated by percent)
O2 sub (subprogram begin) (program end signaled by O2 sub)
(in sub 2)
G0 Z3
(returning from sub 2)
O2 endsub
O1 (main program begin)
G0 X1Y2
(calling sub 2)
O2 call
(returned from sub 2)
(end of main signaled by percent)
%

View file

@ -0,0 +1,44 @@
#!/bin/bash -e
LEGAL_TESTS="
end-main-with-m2
end-main-with-m02
end-main-with-m30
end-main-with-percent
"
ILLEGAL_TESTS="
end-main-with-eof
no-m30-before-osub
sub-after-percent
"
#
# Run legal tests
#
for t in $LEGAL_TESTS; do
echo "Legal test ${t}:"
rs274 -g test-legal-${t}.ngc | awk '{$1=""; print}'
res=${PIPESTATUS[0]}
if test "$res" = 0; then
echo "Success: Test '${t}' exited ${res}" >&2
else
echo "Error: Test '${t}' exited ${res}" >&2
exit "$res"
fi
done
# Run illegal tests
#
for t in $ILLEGAL_TESTS; do
echo "Illegal test ${t}:"
res=-1
rs274 -g test-illegal-${t}.ngc | awk '{$1=""; print}'
res=${PIPESTATUS[0]}
if test "$res" = 0; then
echo "Error: Illegal test '${t}' exited ${res}" >&2
exit "$res"
else
echo "Success: Illegal test '${t}' exited ${res} (non-zero=success)" >&2
fi
done

View file

@ -0,0 +1,3 @@
out.motion-logger
rs274ngc.var
rs274ngc.var.bak

View file

@ -0,0 +1,3 @@
#!/bin/sh
cd $(dirname $1)
diff -u expected.motion-logger out.motion-logger

View file

@ -0,0 +1,30 @@
N..... USE_LENGTH_UNITS(CANON_UNITS_MM)
N..... SET_G5X_OFFSET(1, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000)
N..... SET_G92_OFFSET(0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000)
N..... SET_XY_ROTATION(0.0000)
N..... SET_FEED_REFERENCE(CANON_XYZ)
N..... COMMENT("Endless program")
N..... COMMENT("In a standalone interpreter, this should probably exit")
N..... COMMENT("at the main program M99. In task, the main program M99")
N..... COMMENT("should cause an endless loop, terminated by a counter.")
N..... COMMENT("*****************************************************")
N..... COMMENT("Don't *actually* run this program infinitely!")
N..... COMMENT("loops in case of failure")
N..... COMMENT("Counter; assume it starts at 0")
N..... COMMENT("*****************************************************")
Loop number 1.000000
N..... COMMENT("Junk move...")
N..... SET_FEED_RATE(40.0000)
N..... STRAIGHT_FEED(1.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000)
N..... COMMENT("Subprogram junk move...")
N..... STRAIGHT_FEED(1.0000, -4.0000, 0.0000, 0.0000, 0.0000, 0.0000)
N..... COMMENT("Another junk move...")
N..... STRAIGHT_FEED(5.0000, -4.0000, 0.0000, 0.0000, 0.0000, 0.0000)
N..... COMMENT("Main program endless loop")
N..... SET_G5X_OFFSET(1, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000)
N..... SET_XY_ROTATION(0.0000)
N..... SET_FEED_MODE(0)
N..... SET_FEED_RATE(0.0000)
N..... STOP_SPINDLE_TURNING()
N..... SET_SPINDLE_MODE(0.0000)
N..... PROGRAM_END()

View file

@ -0,0 +1,204 @@
SET_NUM_JOINTS 9
SET_VEL vel=0.000000, ini_maxvel=1.200000
SET_VEL_LIMIT vel=4.000000
SET_ACC acc=999999999999999967336168804116691273849533185806555472917961779471295845921727862608739868455469056.000000
SETUP_ARC_BLENDS
SET_MAX_FEED_OVERRIDE 1.000000
SETUP_SET_PROBE_ERR_INHIBIT 0 0
SET_WORLD_HOME x=0.000000, y=0.000000, z=0.000000, a=0.000000, b=0.000000, c=0.000000, u=0.000000, v=0.000000, w=0.000000
SET_JOINT_BACKLASH joint=0, backlash=0.000000
SET_JOINT_POSITION_LIMITS joint=0, min=-40.000000, max=0.000000
SET_JOINT_POSITION_LIMITS joint=0, min=-40.000000, max=40.000000
SET_JOINT_MAX_FERROR joint=0, maxFerror=0.050000
SET_JOINT_MIN_FERROR joint=0, minFerror=0.010000
SET_JOINT_HOMING_PARAMS joint=0, offset=0.000000 home=0.000000, final_vel=-1.000000, search_vel=0.000000, latch_vel=0.000000, flags=0x00000000, sequence=-1, volatile=0
SET_JOINT_VEL_LIMIT joint=0, vel=4.000000
SET_JOINT_ACC_LIMIT joint=0, acc=1000.000000
JOINT_ACTIVATE joint=0
SET_JOINT_BACKLASH joint=1, backlash=0.000000
SET_JOINT_POSITION_LIMITS joint=1, min=-40.000000, max=0.000000
SET_JOINT_POSITION_LIMITS joint=1, min=-40.000000, max=40.000000
SET_JOINT_MAX_FERROR joint=1, maxFerror=0.050000
SET_JOINT_MIN_FERROR joint=1, minFerror=0.010000
SET_JOINT_HOMING_PARAMS joint=1, offset=0.000000 home=0.000000, final_vel=-1.000000, search_vel=0.000000, latch_vel=0.000000, flags=0x00000000, sequence=-1, volatile=0
SET_JOINT_VEL_LIMIT joint=1, vel=4.000000
SET_JOINT_ACC_LIMIT joint=1, acc=1000.000000
JOINT_ACTIVATE joint=1
SET_JOINT_BACKLASH joint=2, backlash=0.000000
SET_JOINT_POSITION_LIMITS joint=2, min=-4.000000, max=0.000000
SET_JOINT_POSITION_LIMITS joint=2, min=-4.000000, max=4.000000
SET_JOINT_MAX_FERROR joint=2, maxFerror=0.050000
SET_JOINT_MIN_FERROR joint=2, minFerror=0.010000
SET_JOINT_HOMING_PARAMS joint=2, offset=0.000000 home=0.000000, final_vel=-1.000000, search_vel=0.000000, latch_vel=0.000000, flags=0x00000000, sequence=-1, volatile=0
SET_JOINT_VEL_LIMIT joint=2, vel=4.000000
SET_JOINT_ACC_LIMIT joint=2, acc=1000.000000
JOINT_ACTIVATE joint=2
SET_JOINT_BACKLASH joint=3, backlash=0.000000
SET_JOINT_POSITION_LIMITS joint=3, min=-40.000000, max=0.000000
SET_JOINT_POSITION_LIMITS joint=3, min=-40.000000, max=40.000000
SET_JOINT_MAX_FERROR joint=3, maxFerror=0.050000
SET_JOINT_MIN_FERROR joint=3, minFerror=0.010000
SET_JOINT_HOMING_PARAMS joint=3, offset=0.000000 home=0.000000, final_vel=-1.000000, search_vel=0.000000, latch_vel=0.000000, flags=0x00000000, sequence=-1, volatile=0
SET_JOINT_VEL_LIMIT joint=3, vel=4.000000
SET_JOINT_ACC_LIMIT joint=3, acc=1000.000000
JOINT_ACTIVATE joint=3
SET_JOINT_BACKLASH joint=4, backlash=0.000000
SET_JOINT_POSITION_LIMITS joint=4, min=-40.000000, max=0.000000
SET_JOINT_POSITION_LIMITS joint=4, min=-40.000000, max=40.000000
SET_JOINT_MAX_FERROR joint=4, maxFerror=0.050000
SET_JOINT_MIN_FERROR joint=4, minFerror=0.010000
SET_JOINT_HOMING_PARAMS joint=4, offset=0.000000 home=0.000000, final_vel=-1.000000, search_vel=0.000000, latch_vel=0.000000, flags=0x00000000, sequence=-1, volatile=0
SET_JOINT_VEL_LIMIT joint=4, vel=4.000000
SET_JOINT_ACC_LIMIT joint=4, acc=1000.000000
JOINT_ACTIVATE joint=4
SET_JOINT_BACKLASH joint=5, backlash=0.000000
SET_JOINT_POSITION_LIMITS joint=5, min=-4.000000, max=0.000000
SET_JOINT_POSITION_LIMITS joint=5, min=-4.000000, max=4.000000
SET_JOINT_MAX_FERROR joint=5, maxFerror=0.050000
SET_JOINT_MIN_FERROR joint=5, minFerror=0.010000
SET_JOINT_HOMING_PARAMS joint=5, offset=0.000000 home=0.000000, final_vel=-1.000000, search_vel=0.000000, latch_vel=0.000000, flags=0x00000000, sequence=-1, volatile=0
SET_JOINT_VEL_LIMIT joint=5, vel=4.000000
SET_JOINT_ACC_LIMIT joint=5, acc=1000.000000
JOINT_ACTIVATE joint=5
SET_JOINT_BACKLASH joint=6, backlash=0.000000
SET_JOINT_POSITION_LIMITS joint=6, min=-40.000000, max=0.000000
SET_JOINT_POSITION_LIMITS joint=6, min=-40.000000, max=40.000000
SET_JOINT_MAX_FERROR joint=6, maxFerror=0.050000
SET_JOINT_MIN_FERROR joint=6, minFerror=0.010000
SET_JOINT_HOMING_PARAMS joint=6, offset=0.000000 home=0.000000, final_vel=-1.000000, search_vel=0.000000, latch_vel=0.000000, flags=0x00000000, sequence=-1, volatile=0
SET_JOINT_VEL_LIMIT joint=6, vel=4.000000
SET_JOINT_ACC_LIMIT joint=6, acc=1000.000000
JOINT_ACTIVATE joint=6
SET_JOINT_BACKLASH joint=7, backlash=0.000000
SET_JOINT_POSITION_LIMITS joint=7, min=-40.000000, max=0.000000
SET_JOINT_POSITION_LIMITS joint=7, min=-40.000000, max=40.000000
SET_JOINT_MAX_FERROR joint=7, maxFerror=0.050000
SET_JOINT_MIN_FERROR joint=7, minFerror=0.010000
SET_JOINT_HOMING_PARAMS joint=7, offset=0.000000 home=0.000000, final_vel=-1.000000, search_vel=0.000000, latch_vel=0.000000, flags=0x00000000, sequence=-1, volatile=0
SET_JOINT_VEL_LIMIT joint=7, vel=4.000000
SET_JOINT_ACC_LIMIT joint=7, acc=1000.000000
JOINT_ACTIVATE joint=7
SET_JOINT_BACKLASH joint=8, backlash=0.000000
SET_JOINT_POSITION_LIMITS joint=8, min=-4.000000, max=0.000000
SET_JOINT_POSITION_LIMITS joint=8, min=-4.000000, max=4.000000
SET_JOINT_MAX_FERROR joint=8, maxFerror=0.050000
SET_JOINT_MIN_FERROR joint=8, minFerror=0.010000
SET_JOINT_HOMING_PARAMS joint=8, offset=0.000000 home=0.000000, final_vel=-1.000000, search_vel=0.000000, latch_vel=0.000000, flags=0x00000000, sequence=-1, volatile=0
SET_JOINT_VEL_LIMIT joint=8, vel=4.000000
SET_JOINT_ACC_LIMIT joint=8, acc=1000.000000
JOINT_ACTIVATE joint=8
SET_AXIS_POSITION_LIMITS axis=0, min=-40.000000, max=0.000000
SET_AXIS_POSITION_LIMITS axis=0, min=-40.000000, max=40.000000
SET_AXIS_VEL_LIMIT axis=0 vel=4.000000
SET_AXIS_ACC_LIMIT axis=0, acc=1000.000000
SET_AXIS_LOCKING_JOINT axis=0, locking_joint=-1
SET_AXIS_POSITION_LIMITS axis=1, min=-40.000000, max=0.000000
SET_AXIS_POSITION_LIMITS axis=1, min=-40.000000, max=40.000000
SET_AXIS_VEL_LIMIT axis=1 vel=4.000000
SET_AXIS_ACC_LIMIT axis=1, acc=1000.000000
SET_AXIS_LOCKING_JOINT axis=1, locking_joint=-1
SET_AXIS_POSITION_LIMITS axis=2, min=-4.000000, max=0.000000
SET_AXIS_POSITION_LIMITS axis=2, min=-4.000000, max=4.000000
SET_AXIS_VEL_LIMIT axis=2 vel=4.000000
SET_AXIS_ACC_LIMIT axis=2, acc=1000.000000
SET_AXIS_LOCKING_JOINT axis=2, locking_joint=-1
SET_AXIS_POSITION_LIMITS axis=3, min=-40.000000, max=0.000000
SET_AXIS_POSITION_LIMITS axis=3, min=-40.000000, max=40.000000
SET_AXIS_VEL_LIMIT axis=3 vel=4.000000
SET_AXIS_ACC_LIMIT axis=3, acc=1000.000000
SET_AXIS_LOCKING_JOINT axis=3, locking_joint=-1
SET_AXIS_POSITION_LIMITS axis=4, min=-40.000000, max=0.000000
SET_AXIS_POSITION_LIMITS axis=4, min=-40.000000, max=40.000000
SET_AXIS_VEL_LIMIT axis=4 vel=4.000000
SET_AXIS_ACC_LIMIT axis=4, acc=1000.000000
SET_AXIS_LOCKING_JOINT axis=4, locking_joint=-1
SET_AXIS_POSITION_LIMITS axis=5, min=-4.000000, max=0.000000
SET_AXIS_POSITION_LIMITS axis=5, min=-4.000000, max=4.000000
SET_AXIS_VEL_LIMIT axis=5 vel=4.000000
SET_AXIS_ACC_LIMIT axis=5, acc=1000.000000
SET_AXIS_LOCKING_JOINT axis=5, locking_joint=-1
SET_AXIS_POSITION_LIMITS axis=6, min=-40.000000, max=0.000000
SET_AXIS_POSITION_LIMITS axis=6, min=-40.000000, max=40.000000
SET_AXIS_VEL_LIMIT axis=6 vel=4.000000
SET_AXIS_ACC_LIMIT axis=6, acc=1000.000000
SET_AXIS_LOCKING_JOINT axis=6, locking_joint=-1
SET_AXIS_POSITION_LIMITS axis=7, min=-40.000000, max=0.000000
SET_AXIS_POSITION_LIMITS axis=7, min=-40.000000, max=40.000000
SET_AXIS_VEL_LIMIT axis=7 vel=4.000000
SET_AXIS_ACC_LIMIT axis=7, acc=1000.000000
SET_AXIS_LOCKING_JOINT axis=7, locking_joint=-1
SET_AXIS_POSITION_LIMITS axis=8, min=-4.000000, max=0.000000
SET_AXIS_POSITION_LIMITS axis=8, min=-4.000000, max=4.000000
SET_AXIS_VEL_LIMIT axis=8 vel=4.000000
SET_AXIS_ACC_LIMIT axis=8, acc=1000.000000
SET_AXIS_LOCKING_JOINT axis=8, locking_joint=-1
JOINT_ABORT joint=0
JOINT_ABORT joint=1
JOINT_ABORT joint=2
JOINT_ABORT joint=3
JOINT_ABORT joint=4
JOINT_ABORT joint=5
JOINT_ABORT joint=6
JOINT_ABORT joint=7
JOINT_ABORT joint=8
ABORT
SPINDLE_OFF
DISABLE_AMPLIFIER
DISABLE_AMPLIFIER
DISABLE_AMPLIFIER
DISABLE_AMPLIFIER
DISABLE_AMPLIFIER
DISABLE_AMPLIFIER
DISABLE_AMPLIFIER
DISABLE_AMPLIFIER
DISABLE_AMPLIFIER
DISABLE
JOINT_UNHOME joint=-2
FREE
SET_TERM_COND termCond=2, tolerance=0.000000
JOINT_ABORT joint=0
JOINT_ABORT joint=1
JOINT_ABORT joint=2
JOINT_ABORT joint=3
JOINT_ABORT joint=4
JOINT_ABORT joint=5
JOINT_ABORT joint=6
JOINT_ABORT joint=7
JOINT_ABORT joint=8
ABORT
SPINDLE_OFF
SET_SPINDLESYNC sync=0.000000, flags=0x00000000
SPINDLE_OFF
ENABLE
ENABLE_AMPLIFIER
ENABLE_AMPLIFIER
ENABLE_AMPLIFIER
ENABLE_AMPLIFIER
ENABLE_AMPLIFIER
ENABLE_AMPLIFIER
ENABLE_AMPLIFIER
ENABLE_AMPLIFIER
ENABLE_AMPLIFIER
COORD
JOINT_ABORT joint=0
JOINT_ABORT joint=1
JOINT_ABORT joint=2
JOINT_ABORT joint=3
JOINT_ABORT joint=4
JOINT_ABORT joint=5
JOINT_ABORT joint=6
JOINT_ABORT joint=7
JOINT_ABORT joint=8
ABORT
SET_LINE x=1.000000, y=0.000000, z=0.000000, a=0.000000, b=0.000000, c=0.000000, u=0.000000, v=0.000000, w=0.000000, id=19, motion_type=2, vel=0.666667, ini_maxvel=4.000000, acc=1000.000000, turn=-1
SET_LINE x=1.000000, y=-4.000000, z=0.000000, a=0.000000, b=0.000000, c=0.000000, u=0.000000, v=0.000000, w=0.000000, id=26, motion_type=2, vel=0.666667, ini_maxvel=4.000000, acc=1000.000000, turn=-1
SET_LINE x=5.000000, y=-4.000000, z=0.000000, a=0.000000, b=0.000000, c=0.000000, u=0.000000, v=0.000000, w=0.000000, id=21, motion_type=2, vel=0.666667, ini_maxvel=4.000000, acc=1000.000000, turn=-1
SET_LINE x=1.000000, y=0.000000, z=0.000000, a=0.000000, b=0.000000, c=0.000000, u=0.000000, v=0.000000, w=0.000000, id=19, motion_type=2, vel=0.666667, ini_maxvel=4.000000, acc=1000.000000, turn=-1
SET_LINE x=1.000000, y=-4.000000, z=0.000000, a=0.000000, b=0.000000, c=0.000000, u=0.000000, v=0.000000, w=0.000000, id=26, motion_type=2, vel=0.666667, ini_maxvel=4.000000, acc=1000.000000, turn=-1
SET_LINE x=5.000000, y=-4.000000, z=0.000000, a=0.000000, b=0.000000, c=0.000000, u=0.000000, v=0.000000, w=0.000000, id=21, motion_type=2, vel=0.666667, ini_maxvel=4.000000, acc=1000.000000, turn=-1
SET_LINE x=1.000000, y=0.000000, z=0.000000, a=0.000000, b=0.000000, c=0.000000, u=0.000000, v=0.000000, w=0.000000, id=19, motion_type=2, vel=0.666667, ini_maxvel=4.000000, acc=1000.000000, turn=-1
SET_LINE x=1.000000, y=-4.000000, z=0.000000, a=0.000000, b=0.000000, c=0.000000, u=0.000000, v=0.000000, w=0.000000, id=26, motion_type=2, vel=0.666667, ini_maxvel=4.000000, acc=1000.000000, turn=-1
SET_LINE x=5.000000, y=-4.000000, z=0.000000, a=0.000000, b=0.000000, c=0.000000, u=0.000000, v=0.000000, w=0.000000, id=21, motion_type=2, vel=0.666667, ini_maxvel=4.000000, acc=1000.000000, turn=-1
SET_SPINDLESYNC sync=0.000000, flags=0x00000000
SPINDLE_OFF
DISABLE

View file

@ -0,0 +1,3 @@
loadusr -W motion-logger out.motion-logger
setp iocontrol.0.emc-enable-in 1

View file

@ -0,0 +1,217 @@
[EMC]
VERSION = 1.0
DEBUG = 0x0
[DISPLAY]
DISPLAY = ./test-ui.py
[TASK]
TASK = milltask
CYCLE_TIME = 0.001
[RS274NGC]
PARAMETER_FILE = sim.var
[EMCMOT]
#EMCMOT = motmod
COMM_TIMEOUT = 4.0
COMM_WAIT = 0.010
BASE_PERIOD = 0
SERVO_PERIOD = 1000000
[EMCIO]
EMCIO = io
CYCLE_TIME = 0.100
TOOL_TABLE = simpockets.tbl
TOOL_CHANGE_QUILL_UP = 1
RANDOM_TOOLCHANGER = 0
[HAL]
HALFILE = mock-motion.hal
#POSTGUI_HALFILE = postgui.hal
[TRAJ]
NO_FORCE_HOMING = 1
COORDINATES = X Y Z A B C U V W
HOME = 0 0 0 0 0 0 0 0 0
LINEAR_UNITS = inch
ANGULAR_UNITS = degree
CYCLE_TIME = 0.010
DEFAULT_LINEAR_VELOCITY = 1.2
MAX_LINEAR_VELOCITY = 4
[KINS]
KINEMATICS = trivkins
JOINTS = 9
[AXIS_X]
MIN_LIMIT = -40.0
MAX_LIMIT = 40.0
MAX_VELOCITY = 4
MAX_ACCELERATION = 1000.0
[JOINT_0]
TYPE = LINEAR
HOME = 0.000
MAX_VELOCITY = 4
MAX_ACCELERATION = 1000.0
BACKLASH = 0.000
INPUT_SCALE = 4000
OUTPUT_SCALE = 1.000
MIN_LIMIT = -40.0
MAX_LIMIT = 40.0
FERROR = 0.050
MIN_FERROR = 0.010
[AXIS_Y]
MIN_LIMIT = -40.0
MAX_LIMIT = 40.0
MAX_VELOCITY = 4
MAX_ACCELERATION = 1000.0
[JOINT_1]
TYPE = LINEAR
HOME = 0.000
MAX_VELOCITY = 4
MAX_ACCELERATION = 1000.0
BACKLASH = 0.000
INPUT_SCALE = 4000
OUTPUT_SCALE = 1.000
MIN_LIMIT = -40.0
MAX_LIMIT = 40.0
FERROR = 0.050
MIN_FERROR = 0.010
[AXIS_Z]
MIN_LIMIT = -4.0
MAX_LIMIT = 4.0
MAX_VELOCITY = 4
MAX_ACCELERATION = 1000.0
[JOINT_2]
TYPE = LINEAR
HOME = 0.0
MAX_VELOCITY = 4
MAX_ACCELERATION = 1000.0
BACKLASH = 0.000
INPUT_SCALE = 4000
OUTPUT_SCALE = 1.000
MIN_LIMIT = -4.0
MAX_LIMIT = 4.0
FERROR = 0.050
MIN_FERROR = 0.010
[AXIS_A]
MIN_LIMIT = -40.0
MAX_LIMIT = 40.0
MAX_VELOCITY = 4
MAX_ACCELERATION = 1000.0
[JOINT_3]
TYPE = ANGULAR
HOME = 0.000
MAX_VELOCITY = 4
MAX_ACCELERATION = 1000.0
BACKLASH = 0.000
INPUT_SCALE = 4000
OUTPUT_SCALE = 1.000
MIN_LIMIT = -40.0
MAX_LIMIT = 40.0
FERROR = 0.050
MIN_FERROR = 0.010
[AXIS_B]
MIN_LIMIT = -40.0
MAX_LIMIT = 40.0
MAX_VELOCITY = 4
MAX_ACCELERATION = 1000.0
[JOINT_4]
TYPE = ANGULAR
HOME = 0.000
MAX_VELOCITY = 4
MAX_ACCELERATION = 1000.0
BACKLASH = 0.000
INPUT_SCALE = 4000
OUTPUT_SCALE = 1.000
MIN_LIMIT = -40.0
MAX_LIMIT = 40.0
FERROR = 0.050
MIN_FERROR = 0.010
[AXIS_C]
MIN_LIMIT = -4.0
MAX_LIMIT = 4.0
MAX_VELOCITY = 4
MAX_ACCELERATION = 1000.0
[JOINT_5]
TYPE = ANGULAR
HOME = 0.0
MAX_VELOCITY = 4
MAX_ACCELERATION = 1000.0
BACKLASH = 0.000
INPUT_SCALE = 4000
OUTPUT_SCALE = 1.000
MIN_LIMIT = -4.0
MAX_LIMIT = 4.0
FERROR = 0.050
MIN_FERROR = 0.010
[AXIS_U]
MIN_LIMIT = -40.0
MAX_LIMIT = 40.0
MAX_VELOCITY = 4
MAX_ACCELERATION = 1000.0
[JOINT_6]
TYPE = LINEAR
HOME = 0.000
MAX_VELOCITY = 4
MAX_ACCELERATION = 1000.0
BACKLASH = 0.000
INPUT_SCALE = 4000
OUTPUT_SCALE = 1.000
MIN_LIMIT = -40.0
MAX_LIMIT = 40.0
FERROR = 0.050
MIN_FERROR = 0.010
[AXIS_V]
MIN_LIMIT = -40.0
MAX_LIMIT = 40.0
MAX_VELOCITY = 4
MAX_ACCELERATION = 1000.0
[JOINT_7]
TYPE = LINEAR
HOME = 0.000
MAX_VELOCITY = 4
MAX_ACCELERATION = 1000.0
BACKLASH = 0.000
INPUT_SCALE = 4000
OUTPUT_SCALE = 1.000
MIN_LIMIT = -40.0
MAX_LIMIT = 40.0
FERROR = 0.050
MIN_FERROR = 0.010
[AXIS_W]
MIN_LIMIT = -4.0
MAX_LIMIT = 4.0
MAX_VELOCITY = 4
MAX_ACCELERATION = 1000.0
[JOINT_8]
TYPE = LINEAR
HOME = 0.0
MAX_VELOCITY = 4
MAX_ACCELERATION = 1000.0
BACKLASH = 0.000
INPUT_SCALE = 4000
OUTPUT_SCALE = 1.000
MIN_LIMIT = -4.0
MAX_LIMIT = 4.0
FERROR = 0.050
MIN_FERROR = 0.010

View file

@ -0,0 +1,36 @@
#!/usr/bin/env python
import linuxcnc
import hal
import time
import sys
#
# connect to LinuxCNC
#
c = linuxcnc.command()
s = linuxcnc.stat()
e = linuxcnc.error_channel()
#
# Come out of E-stop, turn the machine on, home, and switch to Auto mode.
#
c.state(linuxcnc.STATE_ESTOP_RESET)
c.state(linuxcnc.STATE_ON)
c.mode(linuxcnc.MODE_AUTO)
#
# run the .ngc test file, starting from the special line
#
c.program_open('test.ngc')
c.auto(linuxcnc.AUTO_RUN, 4)
c.wait_complete()
sys.exit(0)

View file

@ -0,0 +1,29 @@
(Endless program)
(In a standalone interpreter, this should probably exit)
(at the main program M99. In task, the main program M99)
(should cause an endless loop, terminated by a counter.)
(*****************************************************)
(Don't *actually* run this program infinitely!)
(Stop after) #101 = 3 (loops in case of failure)
#100 = [#100 + 1] (Counter; assume it starts at 0)
O1000 if [#100 GT #101]
(PRINT, "Stopping program after #101 loops")
#100 = 0 (Reset counter)
M30 (End program)
O1000 endif
(*****************************************************)
O1 (Main program begin)
(PRINT, X Loop number #100)
G1 X1 F40 (Junk move...)
M98 P100 (Call junk subprogram)
G1 X5 (Another junk move...)
M99 (Main program endless loop)
(*****************************************************)
O100 (Junk subprogram begin)
G1 Y-4 (Subprogram junk move...)
M99 (Return to main program)
%

View file

@ -0,0 +1,10 @@
#!/bin/bash -e
rm -f out.motion-logger
# Run test file in task: should loop through program three times
linuxcnc -r motion-logger.ini
# Run test file in stand-alone interpreter: should run program once
rs274 -g test.ngc | awk '{$1=""; print}'
exit ${PIPESTATUS[0]}

View file

@ -0,0 +1,30 @@
1 N..... USE_LENGTH_UNITS(CANON_UNITS_MM)
2 N..... SET_G5X_OFFSET(1, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000)
3 N..... SET_G92_OFFSET(0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000)
4 N..... SET_XY_ROTATION(0.0000)
5 N..... SET_FEED_REFERENCE(CANON_XYZ)
6 N..... COMMENT("test-named.ngc: Test named programs")
7 N..... COMMENT("...program body")
8 N..... SET_G5X_OFFSET(1, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000)
9 N..... SET_XY_ROTATION(0.0000)
10 N..... SET_FEED_MODE(0)
11 N..... SET_FEED_RATE(0.0000)
12 N..... STOP_SPINDLE_TURNING()
13 N..... SET_SPINDLE_MODE(0.0000)
14 N..... PALLET_SHUTTLE()
15 N..... PROGRAM_END()
1 N..... USE_LENGTH_UNITS(CANON_UNITS_MM)
2 N..... SET_G5X_OFFSET(1, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000)
3 N..... SET_G92_OFFSET(0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000)
4 N..... SET_XY_ROTATION(0.0000)
5 N..... SET_FEED_REFERENCE(CANON_XYZ)
6 N..... COMMENT("test-numbered.ngc: Test numbered programs")
7 N..... COMMENT("...program body")
8 N..... SET_G5X_OFFSET(1, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000)
9 N..... SET_XY_ROTATION(0.0000)
10 N..... SET_FEED_MODE(0)
11 N..... SET_FEED_RATE(0.0000)
12 N..... STOP_SPINDLE_TURNING()
13 N..... SET_SPINDLE_MODE(0.0000)
14 N..... PALLET_SHUTTLE()
15 N..... PROGRAM_END()

View file

@ -0,0 +1,6 @@
%
(test-named.ngc: Test named programs)
O<MyProgram>
(...program body)
M30
%

View file

@ -0,0 +1,6 @@
%
(test-numbered.ngc: Test numbered programs)
O42
(...program body)
M30
%

View file

@ -0,0 +1,3 @@
#!/bin/bash -e
rs274 -g test-named.ngc
rs274 -g test-numbered.ngc

View file

@ -0,0 +1,15 @@
1 N..... USE_LENGTH_UNITS(CANON_UNITS_MM)
2 N..... SET_G5X_OFFSET(1, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000)
3 N..... SET_G92_OFFSET(0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000)
4 N..... SET_XY_ROTATION(0.0000)
5 N..... SET_FEED_REFERENCE(CANON_XYZ)
In sub 100
In sub 200
6 N..... SET_G5X_OFFSET(1, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000)
7 N..... SET_XY_ROTATION(0.0000)
8 N..... SET_FEED_MODE(0)
9 N..... SET_FEED_RATE(0.0000)
10 N..... STOP_SPINDLE_TURNING()
11 N..... SET_SPINDLE_MODE(0.0000)
12 N..... PALLET_SHUTTLE()
13 N..... PROGRAM_END()

View file

@ -0,0 +1,21 @@
%
; test calling subprograms with expressions
; call sub O100: use variable in expression with rs274ngc O-sub
#2 = 10
O[#2 * 10] call
; call sub O200: use expression in M98 P-word
M98 P[5 * 5 * 2 * 2 + 100]
M30
O100 sub ; rs274ngc subroutine
(print,In sub 100)
O100 endsub
O200 ; numbered subprogram
(print,In sub 200)
M99
%

View file

@ -0,0 +1,2 @@
#!/bin/bash -e
rs274 -g test.ngc