Production recipe
This scenario example illustrates how the TwinCAT Database Server handles XML files with any structure. The production recipe for building the product is read from an XML file. The corresponding test parameters are read from a different file. In addition, the test results are written into an existing XML file.

Category | SQL Expert mode |
Database used | XML (as free XML documents) |
Compatible databases | XML |
PLC function blocks used | |
PLC libraries used | Tc3_Database, Tc3_Eventlogger |
Download |
Recipe XML:

Test XML:

FB_ProductionConfigData
GetConfig (method)
This method reads the production recipe for a product from an XML file. XPath queries can be used to find the required recipe.
METHOD GetConfig : BOOL
VAR_INPUT
nTypeNum : DINT;
END_VAR
VAR_OUTPUT
stConfig : ST_Config;
END_VAR
GetConfig:= FALSE;
arrPara[0].sParaName := 'rLength';
arrPara[0].eParaType := Tc3_Database.E_ExpParameterType.Float32;
arrPara[0].nParaSize := 4;
arrPara[1].sParaName := 'rWidth';
arrPara[1].eParaType := Tc3_Database.E_ExpParameterType.Float32;
arrPara[1].nParaSize := 4;
arrPara[2].sParaName := 'rHeight';
arrPara[2].eParaType := Tc3_Database.E_ExpParameterType.Float32;
arrPara[2].nParaSize := 4;
arrPara[3].sParaName := 'iQuantity';
arrPara[3].eParaType := Tc3_Database.E_ExpParameterType.Int32;
arrPara[3].nParaSize := 4;
arrPara[4].sParaName := 'iCounter';
arrPara[4].eParaType := Tc3_Database.E_ExpParameterType.Int32;
arrPara[4].nParaSize := 4;
sCmd := CONCAT(CONCAT('XPATH_SEL<SUBTAG>#ProductionConfig/Config[@TypeNum
= ', DINT_TO_STRING(nTypeNum)), ']');
CASE nState_GetConfig OF
0:
IF fbPLCDBCmd.ExecuteDataReturn(
hDBID:= 1,
pExpression:= ADR(sCmd),
cbExpression:= SIZEOF(sCmd),
pData:= 0,
cbData:= 0,
pParameter:= ADR(arrPara),
cbParameter:= SIZEOF(arrPara[0])*5,
nStartIndex:= 0,
nRecordCount:= 1,
pReturnData:= ADR(_stConfig),
cbReturnData:= SIZEOF(_stConfig),
pRecords:= 0) THEN
ipResultEvt := fbPLCDBCmd.ipTcResult;
nState_GetConfig := 100;
END_IF
100:
IF _SetResultInfo(1033) THEN
GetConfig := TRUE;
stConfig := _stConfig;
nState_GetConfig := 0;
END_IF
END_CASE
GetTestParameter (method)
This method reads the product-specific test parameters.
METHOD GetTestParameter : BOOL
VAR_INPUT
nTypeNum : DINT;
END_VAR
VAR_OUTPUT
sTestNum : STRING(8);
stTestPara: ST_TestParameter;
END_VAR
GetTestParameter := FALSE;
CASE nState_GetTestPara OF
0:
arrPara[0].sParaName := 'Test';
arrPara[0].eParaType := Tc3_Database.E_ExpParameterType.STRING_;
arrPara[0].nParaSize := 8;
sCmd := CONCAT(CONCAT('XPATH_SEL<ATTR>#ProductionConfig/Config
[@TypeNum = ', DINT_TO_STRING(nTypeNum)), ']');
IF fbPLCDBCmd.ExecuteDataReturn(
hDBID:= 1,
pExpression:= ADR(sCmd),
cbExpression:= SIZEOF(sCmd),
pData:= 0,
cbData:= 0,
pParameter:= ADR(arrPara),
cbParameter:= SIZEOF(arrPara[0]),
nStartIndex:= 0,
nRecordCount:= 1,
pReturnData:= ADR(_sTestNum),
cbReturnData:= SIZEOF(_sTestNum),
pRecords:= 0) THEN
bError := fbPLCDBCmd.bError;
sErrClass := fbPLCDBCmd.ipTcResultEvent.EventClassDisplayName;
nErrID := fbPLCDBCmd.ipTcResultEvent.EventId;
sErrText := fbPLCDBCmd.ipTcResultEvent.Text;
IF fbPLCDBCmd .bError THEN
ipResultEvt := fbPLCDBCmd.ipTcResult;
nState_GetTestPara:= 100;
ELSE
nState_GetTestPara:= 1;
END_IF
END_IF
1:
arrPara[0].sParaName := 'MaxTemp';
arrPara[0].eParaType := Tc3_Database.E_ExpParameterType.Float32;
arrPara[0].nParaSize := 4;
arrPara[1].sParaName := 'MinTemp';
arrPara[1].eParaType := Tc3_Database.E_ExpParameterType.Float32;
arrPara[1].nParaSize := 4;
arrPara[2].sParaName := 'MaxPSI';
arrPara[2].eParaType := Tc3_Database.E_ExpParameterType.Int32;
arrPara[2].nParaSize := 4;
sCmd := CONCAT(CONCAT('XPATH_SEL<SUBTAG>#ProductionConfig/
TestParameter/Test[@Num = $'', _sTestNum), '$']');
IF fbPLCDBCmd.ExecuteDataReturn(
hDBID:= 2,
pExpression:= ADR(sCmd),
cbExpression:= SIZEOF(sCmd),
pData:= 0,
cbData:= 0,
pParameter:= ADR(arrPara),
cbParameter:= SIZEOF(arrPara[0])*3,
nStartIndex:= 0,
nRecordCount:= 1,
pReturnData:= ADR(_stTest),
cbReturnData:= SIZEOF(_stTest),
pRecords:= 0) THEN
ipResultEvt := fbPLCDBCmd.ipTcResult;
nState_GetTestPara:= 100;
100:
IF _SetResultInfo(1033) THEN
nState_GetTestPara := 0;
stTestPara := _stTest;
sTestNum := _sTestNum;
GetTestParameter := TRUE;
END_IF
END_CASE
AddTestEntry (method)
This method adds the test result to the test XML file.
METHOD AddTestEntry : BOOL
VAR_INPUT
sTestNum : STRING(8);
nTypeNum : DINT;
sTimestamp : STRING;
sTester : STRING;
sResult : STRING;
END_VAR
AddTestEntry := FALSE;
arrPara[0].sParaName := 'TestNum';
arrPara[0].eParaType := Tc3_Database.E_ExpParameterType.STRING_;
arrPara[0].nParaSize := 8;
arrPara[1].sParaName := 'TypeNum';
arrPara[1].eParaType := Tc3_Database.E_ExpParameterType.Int32;
arrPara[1].nParaSize := 4;
arrPara[2].sParaName := 'Timestamp';
arrPara[2].eParaType := Tc3_Database.E_ExpParameterType.STRING_;
arrPara[2].nParaSize := 81;
arrPara[3].sParaName := 'Tester';
arrPara[3].eParaType := Tc3_Database.E_ExpParameterType.STRING_;
arrPara[3].nParaSize := 81;
arrPara[4].sParaName := 'Result';
arrPara[4].eParaType := Tc3_Database.E_ExpParameterType.STRING_;
arrPara[4].nParaSize := 81;
arrPara[5].sParaName := 'Test';
arrPara[5].eParaType := Tc3_Database.E_ExpParameterType.XMLTAGName;
arrPara[5].nParaSize := 0;
sCmd := 'XPATH_ADD<ATTR>#ProductionConfig/Tests';
stTest.sTestNum := sTestNum;
stTest.nTypeNum := nTypeNum;
stTest.sTimestamp := sTimestamp;
stTest.sTester := sTester;
stTest.sResult := sResult;
CASE nState_AddEntry OF
0:
IF fbPLCDBCmd.Execute(
hDBID:= 2,
pExpression:= ADR(sCmd),
cbExpression:= SIZEOF(sCmd),
pData:= ADR(stTest),
cbData:= SIZEOF(stTest),
pParameter:= ADR(arrPara),
cbParameter:= SIZEOF(arrPara)) THEN
ipResultEvt := fbPLCDBCmd.ipTcResult;
nState_AddEntry:= 100;
END_IF
100:
IF _SetResultInfo(1033) THEN
nState_AddEntry:= 0;
AddTestEntry:= TRUE;
END_IF
END_CASE
_SetResultInfo (private method)
The I_Message message interface is evaluated by the TwinCAT EventLogger in the private _SetResultInfo method.
METHOD _SetResultInfo : BOOL
VAR_INPUT
nLangId : INT := 1033;
END_VAR
_SetResultInfo := FALSE;
CASE nState_SetResInfo OF
0:
IF ipResultEvt.RequestEventText(nLangId, EventText, SIZEOF(EventText)) THEN
nState_SetResInfo := 1;
END_IF
1:
IF ipResultEvt.RequestEventClassName(nLangId, EventClassName, SIZEOF(EventClassName)) THEN
EventId := ipResultEvt.nEventId;
bError := (ipResultEvt.eSeverity = TcEventSeverity.Error) OR
(ipResultEvt.eSeverity = TcEventSeverity.Critical);
nState_SetResInfo:=0;
_SetResultInfo := TRUE;
END_IF
END_CASE