Further Samples

The following samples show different types of application of the TC3 XML Server. The PLC-projekt which contains the samples can be downloaded here: TC3_XmlSrv_Samples.zip

Sample 5 shows an initialization once at program startup, Sample 6 shows cyclic and event-driven printing procedures. Both samples again use the structure ST_MYSTRUCT, which in turn includes ST_INNTERSTRUCT. Both Structures are shown in the following:

Structures

TYPE ST_MYSTRUCT:
STRUCT
    fReal    : REAL;
    bBool    : ARRAY [0..2] OF BOOL;
    stInner  : ST_INNTERSTRUCT;
END_STRUCT
END_TYPE 

TYPE ST_INNTERSTRUCT:
STRUCT
    nInteger : INT;
    sString  : STRING;
END_STRUCT
END_TYPE 

Sample 5: One-time initialization at program startup

Sample 5 shows the one-time initialization of value1 on program startup. The function block FB_XmlSrvRead is used.

(* Sample5 reads and initializes value1 when the PLC is started FUNCTIONBLOCK: FB_XmlSrvRead *)

PROGRAM Sample5
VAR
   value1        : ST_MyStruct;
   fbXmlSrvRead  : FB_XmlSrvRead;
   bExecute      : BOOL;
   sFilePath     : T_MaxString := 'C:\Test.xml'; (* CE: '\Hard Disk\Test.xml' *)
   sXPath        : T_MaxString := '/dataentry/MAIN.value1';
   nState        : INT := 0;
END_VAR

CASE nState OF
0: (* initialize *)
   fbXmlSrvRead(
      pSymAddr   := ADR(value1),
      cbSymSize  := SIZEOF(value1), 
      sFilePath  := sFilePath,
      sXPath     := sXPath,
      bExecute   := bExecute
   );
   fbXmlSrvRead(bExecute:= TRUE); 
   nState:= 1; 

1: (* wait for read operation *)
   fbXmlSrvRead(bExecute:= FALSE);
   IF NOT fbXmlSrvRead.bBusy AND NOT fbXmlSrvRead.bError THEN
      nState:= 2; 
   ELSIF fbXmlSrvRead.bError THEN
      nState:= 100;
   END_IF

2: (* operations *)
 ;

100:(* errorState *)
 ;

END_CASE

Sample 6: Cyclic and event-driven writing

The following example generates a new XML file every 20 seconds and writes the familiar structure into it. As usual, the file name is generated based on the current Windows date and time and a string. The write process can also be started by pressing switch (or by setting the switch variable bButton). If the write process is triggered several times within one second, the current file is overwritten.

(* Sample6: Every 20s value1 will be written into a new XML-File named after the current date and 
 time. Furthermore you can activate the printing procedure by pressing a button (or setting the 
 corresponding variable *) 


PROGRAM Sample6
VAR
   value1          : ST_MyStruct;
   fbXmlSrvWrite   : FB_XmlSrvWrite;
 
   sFileFolder     : T_MaxString :='C:\'; (* CE: '\Hard Disk\' *)
   sFileName       : T_MaxString:= '_test.xml';
   sFilePathWrite  : T_MaxString
   (*sFilePathWrite = sFileFolder + time + sFileName*)
 
   sXPathWrite     : T_MaxString :='/dataentry/MAIN.value1';
   ntGetTime       : NT_GetTime;
   stMyTimestruct  : TIMESTRUCT;
   iState          : INT := 1;
   bTwentySec      : BOOL:= FALSE;
   bButton         : BOOL:= FALSE;
   bTwentySecOver  : BOOL;
   triggerWrite    : R_TRIG;
   triggerButton   : R_TRIG;
END_VAR


triggerButton(CLK:= bButton);

CASE iState OF
0: (* idle state *)
 ;
 
1: (* initialize *)
   fbXmlSrvWrite(nMode:=XMLSRV_ADDMISSING, pSymAddr:= ADR(value1),
   cbSymSize:= SIZEOF(value1));
   ntGetTime(START:= TRUE, TIMESTR=>stMyTimestruct); (* get Windows time *)
   IF NOT ntGetTime.BUSY AND NOT ntGetTime.ERR THEN
      iState:= 2;
   ELSIF ntGetTime.ERR THEN
      iState:= 100;
 END_IF
   
2: (* working state *)
   (* change some values - replace with production-process *)
   value1.stInner.nInteger:= value1.stInner.nInteger + 1;
   IF value1.stInner.nInteger = 32767 THEN
      value1.stInner.nInteger:= 0;
   END_IF(* get Windows time *)
   ntGetTime(START:= FALSE);
   IF NOT ntGetTime.BUSY AND NOT ntGetTime.ERR THEN
      ntGetTime(START:= TRUE, TIMESTR=>stMyTimestruct);
   ELSIF ntGetTime.ERR THEN
      iState:= 100;
   END_IF

   (* check if 20s have passed*)
   IF stMyTimestruct.wSecond = 0 OR stMyTimestruct.wSecond = 20 
                    OR stMyTimeStruct.wSecond = 40 THEN
      bTwentySecOver:= TRUE;
      ELSE
      bTwentySecOver:= FALSE;
   END_IF

   (* if 20s have passed => trigger writing-process *)
   triggerWrite(CLK:=bTwentySecOver);
   IF (triggerWrite.Q OR triggerButton.Q) AND NOT fbXmlSrvWrite.bBusy AND NOT fbXmlSrvWrite.bError THEN 
      (* create filename *)
      sFilePathWrite:= CONCAT(sFileFolder, SYSTEMTIME_TO_STRING(stMyTimestruct)); (* set folder + time *)
      sFilePathWrite:= DELETE(STR:= sFilePathWrite, LEN:= 4 , POS:= LEN(STR:=sFilePathWrite)-3); (* delete milliseconds *)
      sFilePathWrite:= REPLACE(STR1:= sFilePathWrite , STR2:= '.' , L:= 1, 
      P:= LEN(STR:=sFilePathWrite)-2); (* replace colon with point *)
      sFilePathWrite:= REPLACE(STR1:= sFilePathWrite , STR2:= '.' , L:= 1, 
      P:= LEN(STR:=sFilePathWrite)-5); (* replace colon with point *)
      sFilePathWrite:= CONCAT(sFilePathWrite, sFileName); (* add filename (default: test) *)

      (*change value 1*)
      value1.stInner.sString := sFilePathWrite;
      value1.stInner.nInteger := stMyTimestruct.wSecond;

      (* write *)
      fbXmlSrvWrite(sFilePath:=sFilePathWrite, sXPath:=sXPathWrite, bExecute:= TRUE);

   ELSIF fbXmlSrvWrite.bError THEN
      iState:= 100;
   END_IF

   (* reset fbXmlSrvWrite *)
   IF fbXmlSrvWrite.bBusy AND NOT tGetTime.ERR THEN
      fbXmlSrvWrite(bExecute:= FALSE);
   ELSIF ntGetTime.ERR THEN
      iState:= 100;
   END_IF
 
100: (* error state*) 
 ;

END_CASE

Requirements

Development environment

Target system type

PLC libraries to be linked

TwinCAT v3.1 Build 4011

PC or CX (x86, x64, ARM)

Tc2_XmlDataSrv