A channel of this control understands the program language of the
SINUMERIK 840D in addition to the RS274 G-code of LinuxCNC
([cha:g-codes], [cha:o-codes]). The reference is the Siemens
"Programming Manual Fundamentals" (11/2006, 6FC5398-1BP10-2AA0): chapter
10 "Arithmetic parameters and program jumps", chapter 11 "Program section
repetition", the instruction list 12.1 and the data types 12.4.4. The
control structures (IF/ELSE/ENDIF, LOOP, FOR, WHILE,
REPEAT/UNTIL, CASE) and the variable definition follow the
"Programming Manual Job Planning", chapter "Flexible NC programming", to
which the Fundamentals manual refers.
Everything here is an addition: a program written for LinuxCNC runs
unchanged. A block is recognised as a Siemens block by its start (an
assignment such as R1=, later a label, a keyword) or by a value assigned
to an address (X=R1*2). Keywords and names are case-insensitive.
This chapter grows with the implementation; the parts that exist are marked, the rest is the plan.
R parameters (implemented)
The arithmetic parameters R0 to R99 hold numbers (the count is the
INI key [RS274NGC]R_PARAMETERS, default 100). They are global to the
channel: every program level sees the same values, they keep their
values across program ends, machine restarts and power cycles. The
interpreter writes them to the file [RS274NGC]R_PARAMETER_FILE (default
rparams.txt next to the INI file) at program end, reset and shutdown
and reads the file at start. The file holds one Rn=value line per
parameter and may be edited while the machine is off.
R1=10 R2=2.5 ; two assignments in one block
N20 R3=R1*R2+1 R4=R3 DIV 4 R5=R3 MOD 4
R6=SQRT(R1*R1+R2*R2)
R[11]=R[1]+R[2] ; the parameter number as an expression
R9=-0.1EX-5 ; exponent notation: -0.000001
G0 X=R1 Y=R2 Z=R3-26 ; values assigned to addresses
F=R10
An assignment is Rn=<expression> or R[<expression>]=<expression>.
Several assignments may follow each other in one block; they are
executed in sequence, so the second sees the result of the first. The
assignments stand at the start of the block; an RS274 word may follow
them (the rest of the block is read as usual). A block number Nnnn and
the block delete / go in front. The comment character of the Siemens
language is ;; the text in parentheses is a comment as in RS274.
The R parameters of a program are separate from the main-run variables
$R[n] (#<_r[n]>) of the synchronized actions
([cha:synchronized-actions]), which belong to the real-time part.
Values assigned to addresses (implemented)
Every address that takes a value can be written as
<address>=<expression>: X=R1, Y=-R7, F=R10*2, S=R20,
X=SIN(R1)*R2+10. The exceptions of the Siemens language are N, G
and L (and the o-word). The expression ends at the next word: G1
X=R1+1 Y=R2 F=R3. The machine axis names of the multi-channel notation
keep their form: X1=R1+5 ([cha:multichannel-gcode]).
The RS274 parameters are operands of the expressions: X=1*2,
Y=<_x>+R2. An RS274 expression in brackets may also follow the equals
sign, X=[#1+1] is the same as X[#1+1].
The expression is evaluated when the block is read, as the RS274 expressions in brackets are, and the number takes its place in the block. The value must be a number; a string is an error.
Expressions (implemented)
The expressions use parentheses for grouping, the usual arithmetic and the Siemens comparison, logic and bit operators. The operator priorities are those of the Siemens language, highest first:
| Priority | Operators | Meaning |
|---|---|---|
1 |
|
grouping, functions |
2 |
|
logical negation, bitwise negation, sign |
3 |
|
multiplication, division, integer division, modulo (also for real numbers) |
4 |
|
addition, subtraction |
5 |
|
bitwise AND |
6 |
|
bitwise exclusive OR |
7 |
|
bitwise OR |
8 |
|
logical AND |
9 |
|
logical exclusive OR |
10 |
|
logical OR |
11 |
|
string concatenation |
12 |
|
comparison (result |
The comparisons bind weakest, as in the Siemens language: a compound
condition is written with parentheses, (R1>5) AND (R2<3). Logical
operators treat 0 as FALSE and every other number as TRUE; the bit
operators work on the integer part of their operands.
Operands: numbers (12, 1.5, .5, with the exponent EX: 1.874EX8,
-0.1EX-5), the constants TRUE and FALSE, hexadecimal and binary
constants in quotes ('HFF', 'B101'), strings in double quotes
("N"<<R10 gives "N100"), R parameters (R1, R[R2+1]), RS274
parameters (1, <name>) and, from the next phase, program variables.
Functions, angles in degrees:
| Function | Result |
|---|---|
|
sine, cosine, tangent |
|
arc sine, arc cosine (degrees) |
|
arc tangent of y/x with the quadrant (degrees) |
|
square root |
|
absolute value |
|
square |
|
integer part |
|
rounded to the nearest integer |
|
natural logarithm, exponential function |
|
the smaller, the larger value |
|
x limited to the range min..max |
|
length of a string |
|
upper / lower case |
|
part of a string, start 0-based |
|
first / last position of a character, first position of any character of a set (-1 if absent) |
|
whether a string is a number, the number |
Errors (unknown function or variable, division by zero, a square root of a negative number, an R parameter outside the range) stop the program with a message naming the block and the column.
Program variables (implemented)
A program declares its own variables with DEF:
DEF INT ZAHL1, ZAHL2=4 ; two integers, the second initialised
DEF REAL WERT=2.5, FELD[2,3] ; a real number and a 2 x 3 array
DEF BOOL FLAG=TRUE
DEF CHAR CH="A" ; a character: its code 0..255
DEF STRING[10] NAME="Marke2" ; a string of up to 10 characters
DEF REAL LISTE[3]=SET(1,2,3), VOLL[2]=REP(7)
ZAHL1=ZAHL2*2+0.4 ; 8: an INT rounds
FELD[1,2]=WERT*4 FELD[0,0]=1 ; array elements, indices from 0
NAME=NAME<<"X"
G0 X=ZAHL1 Y=FELD[1,2] Z=LISTE[2]+VOLL[1]
The types are INT (integer, a real value is rounded), REAL, BOOL
(TRUE/FALSE, every number but 0 is TRUE), CHAR (a character code
0..255, assigned as a number or a string of one character) and
STRING[n] (up to n characters). A DEF block holds one type and any
number of names separated by commas, each with an optional initial
value; nothing else may follow in the block. Arrays have up to three
dimensions in brackets, SET(v1, v2, …) initialises the elements in
order (the rest stays 0), REP(v) sets all of them. A name has at least
two characters and starts with two letters or underscores (so that it
differs from an address with a number); names are case-insensitive.
A variable is assigned with NAME=<expression> or NAME[i,j]=<expression>
at the start of a block, several assignments in one block are allowed,
also together with R parameter assignments, and an RS274 word may follow.
Assigning a string to a numeric variable, a number to a string, a string
longer than the declared length or an index outside the array is an
error, as is a name that is not defined or defined twice.
Variables belong to the program level that defines them: those of the
main program live until its end (M2, M30), a reset or a new program,
those defined inside a subroutine (O… sub) until it returns, and are
defined afresh at every call. A subroutine does not see the variables of
the main program (as in the Siemens language; pass values as subroutine
parameters or through R parameters).
Labels and jumps (implemented)
A block starts with an optional block number and an optional label: a
name of 2 to 32 characters, the first two letters or underscores, followed
by a colon. The rest of the block is any statement, MARKE_1: R1=R1+1,
POS1: G0 X1 Y1 or a label alone. Labels and block numbers are jump
targets:
N20 GOTOF MARKE_0 ; forward to the label
N40 MARKE_1: R1=R1+1
N50 G0 X=R1
N60 MARKE_0: IF R1<3 GOTOB MARKE_1 ; back while the condition holds
N70 GOTOF N100 ; forward to the block number (also GOTOF 100)
N140 IF R2<2 GOTO MARKE_0 ; forward first, then from the start of the program
N150 GOTOF "ENDE"<<"_1" ; the target from a string expression
GOTOB searches backward (toward the start of the program), GOTOF
forward, GOTO forward and then from the start, GOTOC like GOTO but
continues with the next block when the target does not exist (the others
stop the program with the error "jump target not found (14080)"). The
target is a label, a block number (N100 or 100), a STRING variable
holding one, or a string expression. IF <condition> GOTO… <target>
jumps when the condition is TRUE; several conditional jumps may follow
in one block. A jump statement takes the whole block (a comment may
follow).
A jump runs when the block is read; the blocks jumped over are not executed. Jumps are possible in programs only, not in MDI.
Program section repetition (implemented)
N20 BEGIN: R10=R10+1
N30 G0 X=R10
N40 ENDE: G0 Y=R10
N50 REPEAT BEGIN ENDE P=2 ; the blocks N20..N40 twice
N70 POS1: G0 X1 Y1
N80 REPEATB POS1 P=2 ; the block N70 twice
N100 ANF: G0 X2
N120 ENDLABEL: G0 Z3
N140 REPEAT ANF ; N100..N120 once (up to ENDLABEL)
N160 LOOP1: G0 X3
N170 G0 Y3
N180 REPEAT LOOP1 P=2 ; N160..N170 twice (up to the REPEAT block)
REPEATB <label> [P=n] executes the labelled block n times (once without
P). REPEAT <start> [<end>] [P=n] executes the section from the start
label n times: up to the end label, or, without an end label, up to the
predefined label ENDLABEL, or up to the REPEAT block itself when
neither is found before it. The block carrying the end label belongs to
the section; the REPEAT block does not. After the last pass the program
continues behind the REPEAT block. The start label is searched backward
first, then forward (so the section may follow the REPEAT block);
repetitions may be nested, each takes a level of its own. P=0 does
nothing.
Control structures (implemented)
The structures of the Job Planning manual ("Flexible NC programming"), each keyword on a block of its own, nested as needed:
IF R1>3 ; a branch, ELSE optional
G0 X1
ELSE
G0 X98
ENDIF
WHILE ZAEHLER<3 ; the condition before every pass
ZAEHLER=ZAEHLER+1
ENDWHILE
FOR II=1 TO 3 ; the variable counts up by 1, the end value fixed at entry
SUMME=SUMME+II
ENDFOR
REPEAT ; at least one pass, the condition after it
ZAEHLER=ZAEHLER-1
UNTIL ZAEHLER<=0
LOOP ; endless, left with a jump
R2=R2+1
IF R2>=2 GOTOF RAUS
ENDLOOP
RAUS: CASE R2 OF 1 GOTOF EINS 2 GOTOF ZWEI DEFAULT GOTOF SONST
IF <condition> without a GOTO opens a branch (with it, it is the
conditional jump of the previous section). The loop variable of FOR is
an INT or REAL variable (DEF) or an R parameter; the start and end
values are expressions. CASE <expression> OF compares with the
constants that follow and jumps to the target of the first match, to the
DEFAULT target when none matches, or continues without a DEFAULT.
The structures and the program section repetition may be combined but
must not overlap; a jump out of a loop leaves it (the loop is forgotten
at the end of the program). A keyword without its opening counterpart
(ELSE without IF, ENDWHILE without WHILE) and a program that ends
inside a structure are errors.
Main-run variables in the part program (implemented)
The main-run variables of the synchronized actions can be read in
ordinary blocks too: $A_IN[n] and $A_INA[n] (motion’s digital and
analog inputs), $A_OUT[n] and $A_OUTA[n] (its outputs), $AA_IM[X]
and $AA_IW[X] (machine and work position of an axis, a plain letter)
and $P_PROG_EVENT (the event number while an event program runs, see
the tool management chapter). As on the SINUMERIK a block that reads one
of them causes an implicit read-ahead stop: the interpreter puts the
block back, lets the queued motion finish and reads it again, so the
values belong to the moment the block is reached:
G1 X=120 F500
IF $A_IN[2] == 1 ; the input as it is after the move
GOTOF FERTIG
ENDIF
R5 = $A_INA[0]
G4 P=R5*0.001
Assignments to outputs are written the same way: $A_OUT[n] = 1 or
0 is M64 Pn / M65 Pn (immediate), $A_OUTA[n] = value is
M68 En Qvalue. The values are also available to RS274 blocks as
<_a_in[n]>, <_a_ina[n]>, <_a_out[n]>, <_a_outa[n]> and
#<_p_prog_event> (without the read-ahead stop; M66 … L0 where it
matters). In MDI the values are read at once, the queue is empty there.