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.

Production recipe 1:

Category

SQL Expert mode

Database used

XML (as free XML documents)

Compatible databases

XML

PLC function blocks used

FB_PLCDBCmdEvt

PLC libraries used

Tc3_Database, Tc3_Eventlogger

Download

TF6420_Sample4_XMLProductionConfig.zip

Recipe XML:

Production recipe 2:

Test XML:

Production recipe 3:

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