Skip to main content

CNC Example 17: Read G-Code from Strings

See the CNC17_ReadGCodeFromStrings.project sample project in the installation directory of CODESYS under ..\CODESYS SoftMotion\Examples.

The sample project shows how to use SMC_StringStream2 to read G-code from a string.

This example can be seen as a starting point and used to read G-code from other sources, for example via network communication (sockets). In this case, a function block needs to be implemented which implements the SMC_ITextStream interface and reads the text (for example, from a socket). This is similar to how SMC_StringStream2 implements this interface to read the G-code from a string.

Structure of the application

The structure is typical for CNC applications. The G-code is read in the background task (PathTask), and path preprocessing also takes place here. The interpolation is performed in the bus task.

In the Path program, the SMC_ReadNCFromStream function block is used to read the G-code. For technical reasons, not only a stream of type SMC_StringStream2 is passed to this function block, but also an array whose size depends on the parameter SMC_CNC_LibParams.MAX_SUBPROGRAM_NESTING_DEPTH. The first stream in the array is used for the main program, while the other streams are used for possible subprogram calls.

At the beginning, the main program is loaded into the first stream of the array:

// Load G-Code into first stream
aStringStream[0].Init(sProgramName) ;
aStringStream[0].AppendData(sGCode) ;
aStringStream[0].SetEndOfData() ;

Then everything is prepared for reading the usual G-code programs. The example also shows how subprogram calls can be supported.

To do this, it is necessary to create a function block which implements the SMC_INCLookup interface. This function block is responsible for returning the G-code of a subprogram when it is read by SMC_ReadNCFromStream. The Lookup method receives the name of the subprogram and initializes an incoming stream with the G-code:

METHOD LookUp : SMC_ERROR
VAR_IN_OUT CONSTANT
    programName : STRING;
END_VAR
VAR_INPUT
    stream : SMC_ITextStream;
END_VAR
VAR
    i : UDINT ;
    pStringStream : POINTER TO SMC_StringStream2 ;
END_VAR

This example searches through an array of subprograms. The array is defined in the Path program as VAR_INPUT:

   // The table of subprograms.
   aSubs : ARRAY[0..0] OF SubProgram := [
            (stName := 'SUB1',
             stContent := '
SUBPROGRAM SUB1{#p1 : LREAL, #p2 : LREAL, #p3 : LREAL}
N10 G1 X#p1
N20 G1 X#p2
N30 G1 X#p3
END_SUBPROGRAM')
        ] ;

In Lookup, the array is iterated through until a subprogram with a matching name is found:

i := 0 ;
WHILE i < nNumSPs DO
    IF psp[i].stName = programName THEN
        IF NOT __QUERYPOINTER(stream, pStringStream) OR_ELSE
           pStringStream = 0
        THEN
            // A stream of the wrong type has been passed by SMC_ReadNCFromStream.
            LookUp := SMC_CNC_INTERNAL_ERROR ;
        ELSE
            pStringStream^.Init(sName := psp[i].stName) ;
            LookUp := pStringStream^.AppendData(psp[i].stContent) ;
            pStringStream^.SetEndOfData() ;
        END_IF
        RETURN ;
    END_IF

    i := i + 1 ;
END_WHILE
 
// No subprogram with name programName has been found in the array psp.
LookUp := SMC_RNCF_SUBPROGRAM_FILE_NOT_FOUND ;

Commissioning

  1. Build the application and download it to a controller.

  2. Open the visualization.

  3. Press Start to start the G-code processing.