summaryrefslogtreecommitdiff
path: root/docs/src/gcode/o-code.txt
blob: 69d56c5d3916cef71a2e9696f4e6585729a1d292 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
= O Codes

[[cha:O-Codes]] (((O Codes)))

O-codes provide for flow control in NC programs. Each block has an
associated number, which is the number used after O. Care must be taken
to properly match the O-numbers. O codes use the letter 'O' not the
number zero as the first character in the number like O100.

.Numbering Example
----
o100 sub
(notice that the if-endif block uses a different number)
  o110 if [#2 GT 5]
    (some code here)
  o110 endif
  (some more code here)
o100 endsub
----

The behavior is undefined if:

* The same number is used for more than one block
* Other words are used on a line with an O- word
* Comments are used on a line with an O-word

[NOTE]
Using the lower case o makes it easier to distinguish from a 0
that might have been mistyped. For example o100 is easier to
see than O100 that it is not a 0.

The following statements  cause an error message and  abort the
interpreter:

 - a `return` or `endsub` not within a sub defintion
 - a label on `repeat` which is defined elsewhere
 - a label on `while` which is defińed elsewhere and not referring to a `do`
 - a label on `if` defined elsewhere
 - a undefined label on `else` or `elseif`
 - a label on `else`, `elseif` or `endif` not pointing to a matching `if`
 - a label on `break` or `continue` which does not point to a matching `while` or `do`
 - a label on `endrepeat` or `endwhile` no referring to a corresponding `while` or `repeat`
    
To make these errors non-fatal  warnings on stderr, set bit 0x20 in
the `[RS274NGC]FEATURE=` mask ini option. 

[[sec:subroutines]]
== Subroutines
(((Subroutines)))
(((sub)))(((endsub)))(((return)))(((call)))

Subroutines extend from a 'O- sub' to an 'O- endsub' . The lines
between 'O- sub' and 'O- endsub' are not executed until
the subroutine is called with 'O- call'. 

.Subroutine Example
----
o100 sub
  G53 G0 X0 Y0 Z0 (rapid move to machine home)
o100 endsub
...
o100 call (call the subroutine here)
M2
----
See <<sec:G53-Move-in,G53>> & <<sec:G0,G0>> & <<sec:M2-M30,M2>> sections for more information.

.O- Return
Inside a subroutine, 'O- return' can be executed. This immediately
returns to the calling code, just as though 'O- endsub' was encountered.

.O- Return Example
----
o100 sub
  o110 if [#2 GT 5] (test if parameter #2 is greater than 5)
    o100 return (return to top of subroutine if test is true)
  o110 endif
  (some code here that only gets executed if parameter #2 is less than 5)
o100 endsub
----
See the <<sec:Binary-Operators,Binary Operators>> & <<sec:parameters,Parameters>> sections for more information.

.O- Call
'O- Call' takes up to 30 optional arguments, which are passed to the
subroutine
 as '#1', '#2' , ..., #N. Parameters from #N+1 to #30 have the same
value as in the
calling context. On return from the subroutine, the values of
parameters #1 through #30 (regardless of the number of arguments) will
be restored to the values they had before the call. Parameters #1 - #30
are local to the subroutine.

Because '1 2 3' is parsed as the number 123, the parameters must be
enclosed in
square brackets. The following calls a subroutine with 3 arguments:

.O- Call Example
----
o200 call [1] [2] [3]
----

Subroutine bodies may not be nested. They may only be called after
they are defined. They may be called from other functions, and may call
themselves recursively if it makes sense to do so. The maximum
subroutine nesting level is 10.

Subroutines do not have 'return values', but they may change the value
of parameters above #30 and those changes will be visible to the
calling code. Subroutines may also change the value of global named
parameters.

[[sec:looping]]
== Looping
(((Looping)))(((do)))(((while)))(((endwhile)))(((break)))(((continue)))

The 'while loop' has two structures: 'while/endwhile', and 'do/while'. In
each case, the loop is exited when the 'while' condition evaluates to
false. The difference is when the test condition is done. The 'do/while'
loop runs the code in the loop then checks the test condition. The
'while/endwhile' loop does the test first.

.While Endwhile Example
----
(draw a sawtooth shape)
G0 X1 Y0 (move to start position)
#1 = 1 (assign parameter #1 the value of 0)
F25 (set a feed rate)
o101 while [#1 LT 10]
  G1 X0
  G1 Y[#1/10] X1
  #1 = [#1+1] (increment the test counter)
o101 endwhile
M2 (end program)
----

.Do While Example
----
#1 = 0 (assign parameter #1 the value of 0)
o100 do
  (debug, parameter 1 = #1)
  o110 if [#1 EQ 2]
    #1 = 3 (assign the value of 3 to parameter #1)
    (msg, #1 has been assigned the value of 3)
    o100 continue (skip to start of loop)
  o110 endif
  (some code here)
  #1 = [#1 + 1] (increment the test counter)
o100 while [#1 LT 3]
(msg, Loop Done!)
M2
----


Inside a while loop, 'O- break' immediately exits the loop, and 'O-
continue' immediately skips to the next evaluation of the 'while'
condition. If it is still true, the loop begins again at the top. If
it is false, it exits the loop.

[[sec:conditional]]
== Conditional
(((Conditional: if, elseif, else, endif)))(((if)))(((else)))(((elseif)))(((endif)))

The 'if' conditional consists of a group of statements with the same 'o' number
that start with 'if' and end with 'endif'. Optional 'elseif' and 'else' conditions
may be between the starting 'if' and the ending 'endif'.

If the 'if' conditional evaluates to true then the group of statements
following the 'if' up to the next conditional line are executed. 

If the 'if' conditional evaluates to false then the 'elseif' conditions are
evaluated in order until one evaluates to true. If the 'elseif' condition is
true then the statements following the 'elseif' up to the next conditional
line are executed. If none of the 'if' or 'elseif' conditions evaluate to true
then the statements following the 'else' are executed. When a condition is
evaluated to true no more conditions are evaluated in the group.

.If Endif Example
----
o101 if [#31 EQ 3] (if parameter #31 is equal to 3 set S2000)
  S2000
o101 endif
----

.If ElseIf Else EndIf Example
----
o102 if [#2 GT 5] (if parameter #2 is greater than 5 set F100)
  F100
o102 elseif [#2 LT 2] (else if parameter #2 is less than 2 set F200)
  F200
o102 else (else if parameter #2 is 2 through 5 set F150)
  F150
o102 endif
----

Several conditons may be tested for by 'elseif' statements until the
'else' path is finally executed if all preceding conditons are false:

.If Elseif Else Endif Example
----
O102 if [#2 GT 5] (if parameter #2 is greater than 5 set F100)
  F100
O102 elseif [#2 LT 2] (else if parameter #2 less than 2 set F200)
  F20
O102 else (parameter #2 between 2 and 5)
  F200
O102 endif
----

[[sec:repeat]]
== Repeat(((Repeat)))

The 'repeat' will execute the statements inside of the
repeat/endrepeat the specified number of times. The example shows how
you might mill a diagonal series of shapes starting at the present
position.

.Repeat Example
----
(Mill 5 diagonal shapes)
G91 (Incremental mode)
o103 repeat [5]
... (insert milling code here)
G0 X1 Y1 (diagonal move to next position)
o103 endrepeat
G90 (Absolute mode)
----

== Indirection(((Indirection)))

The O-number may be given by a parameter and/or calculation.

.Indirection Example
----
o[#101+2] call
----

.Computing values in O-words
For more information on computing values see the following sections

* <<sec:Parameters,Parameters>>
* <<sec:Expressions,Expressions>>
* <<sec:Binary-Operators,Binary Operators>>
* <<sub:functions,Functions>>

== Calling Files(((Calling Files)))

To call a separate file with a subroutine name the file the same as
your call and include a sub and endsub in the file. The file must be in the
directory pointed to by 'PROGRAM_PREFIX' or 'SUBROUTINE_PATH' in the ini file.
The file name can include *lowercase* letters, numbers, dash, and underscore
only. A named subroutine file can contain only a single subroutine definition.

.Named File Example
----
o<myfile> call
----

.Numbered File Example
----
o123 call
----

In the called file you must include the oxxx sub and endsub and the
file must be a valid file.

.Called File Example
----
(filename myfile.ngc)
o<myfile> sub
  (code here)
o<myfile> endsub
M2
----

[NOTE]
The file names are lowercase letters only so 'o<MyFile>' is converted to 'o<myfile>'
by the interpreter. More information about the search path and options for the
search path are in the INI Configuration Section.

== Subroutine return values(((Return Values)))

Subroutines may optionally return a value by an optional expression at
an 'endsub' or 'return' statement.

.Return value example
----
o123 return [#2 *5]
...
o123 endsub [3 * 4]
----

A subroutine return value is stored in the '#<_value>'
<<sec:Predefined-Named-Parameters, predefined named parameter>> , and
the '#<_value_returned>' predefined parameter is set to 1, to indicate
a value was returned. Both paramters are global, and are cleared just
before the next subroutine call.

// vim: set syntax=asciidoc: