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

( ), function calls

grouping, functions

2

NOT, B_NOT, unary -

logical negation, bitwise negation, sign

3

*, /, DIV, MOD

multiplication, division, integer division, modulo (also for real numbers)

4

+, -

addition, subtraction

5

B_AND

bitwise AND

6

B_XOR

bitwise exclusive OR

7

B_OR

bitwise OR

8

AND

logical AND

9

XOR

logical exclusive OR

10

OR

logical OR

11

<<

string concatenation

12

==, <>, >, <, >=, ⇐

comparison (result TRUE = 1, FALSE = 0)

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

SIN(x), COS(x), TAN(x)

sine, cosine, tangent

ASIN(x), ACOS(x)

arc sine, arc cosine (degrees)

ATAN2(y, x)

arc tangent of y/x with the quadrant (degrees)

SQRT(x)

square root

ABS(x)

absolute value

POT(x)

square

TRUNC(x)

integer part

ROUND(x)

rounded to the nearest integer

LN(x), EXP(x)

natural logarithm, exponential function

MINVAL(a, b), MAXVAL(a, b)

the smaller, the larger value

BOUND(min, max, x)

x limited to the range min..max

STRLEN(s)

length of a string

TOUPPER(s), TOLOWER(s)

upper / lower case

SUBSTR(s, start[, length])

part of a string, start 0-based

INDEX(s, c), RINDEX(s, c), MINDEX(s, set)

first / last position of a character, first position of any character of a set (-1 if absent)

ISNUMBER(s), NUMBER(s)

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.

INI keys

Key Meaning

[RS274NGC]R_PARAMETERS

number of R parameters (default 100: R0..R99)

[RS274NGC]R_PARAMETER_FILE

the file holding them (default rparams.txt, relative to the INI directory)