Message logger
This scenario example illustrates the PLC Expert Mode for a Message Logger in the PLC. In the sample program the function blocks of the TwinCAT Database Server are used to create a function block, which provides various methods for generating and reading messages. The database in which the messages are stored is created from the PLC. A sample application of the created function block is implemented in the MAIN program. A new database file is created every 7 days. Three different messages can be sent. In addition it is possible to call up the last message or all messages from a particular interval.

Category | PLC Expert Mode |
Database used | |
Compatible databases | Can be used with minor amendments for all supported database types |
PLC function blocks used | FB_PLCDBCreateEvt, FB_PLCDBCmdEvt, FB_PLCDBWriteEvt, FB_PLCDBReadEvt |
PLC libraries used | Tc3_Database, Tc3_Eventlogger |
Download |
FB_ErrorLogger
CreateErrorLogDB (method)
The CreateErrorLogDB method creates an MS Compact database file and the table in which the messages are stored.
METHOD CreateErrorLogDB : BOOL
VAR_INPUT
sDBName : T_MaxString;
END_VAR
CASE nState_CreateDB OF
0:
stDBConfig.sServer := CONCAT(CONCAT(sDBPath, sDBName), '.sdf');
stDBConfig.bAuthentification := FALSE;
nState_CreateDB := 1;
1:
IF fbPLCDBCreate.Database(pDatabaseConfig:= ADR(stDBConfig),
cbDatabaseConfig:= SIZEOF(stDBConfig),
bCreateXMLConfig:= FALSE, pDBID:= 0) THEN
ipResultEvt := fbPLCDBCreate.ipTcResult;
IF fbPLCDBCreate.bError THEN
nState_CreateDB := 100;
ELSE
nState_CreateDB := 2;
END_IF
END_IF
2:
IF fbConfigTcDBSrv.Create(pTcDBSrvConfig:= ADR(stDBConfig),
cbTcDBSrvConfig:= SIZEOF(stDBConfig), bTemporary:= TRUE,
pConfigID:= ADR(nDBID) ) THEN
ipResultEvt := fbConfigTcDBSrv.ipTcResult;
IF fbConfigTcDBSrv.bError THEN
nState_CreateDB := 100;
ELSE
nState_CreateDB := 3;
END_IF
END_IF
3:
arrTableColumns[0].sName := 'ID';
arrTableColumns[0].eType := E_ColumnType.BigInt;
arrTableColumns[0].nLength := 8;
arrTableColumns[0].sProperty := 'IDENTITY(1,1)';
arrTableColumns[1].sName := 'Timestamp';
arrTableColumns[1].eType := E_ColumnType.DateTime;
arrTableColumns[1].nLength := 4;
arrTableColumns[2].sName := 'Severity';
arrTableColumns[2].eType := E_ColumnType.NVarChar;
arrTableColumns[2].nLength := 10;
arrTableColumns[3].sName := 'ErrorCode';
arrTableColumns[3].eType := E_ColumnType.Integer;
arrTableColumns[3].nLength := 4;
arrTableColumns[4].sName := 'Message';
arrTableColumns[4].eType := E_ColumnType.NVarChar;
arrTableColumns[4].nLength := 255;
IF fbPLCDBCreate.Table(hDBID:= nDBID, sTableName:= sTableName,
pTableCfg:= ADR(arrTableColumns),
cbTableCfg:= SIZEOF(arrTableColumns)) THEN
ipResultEvt := fbPLCDBCreate.ipTcResultEvent;
nState_CreateDB := 100;
END_IF
100:
IF _SetResultInfo(1033) THEN
IF NOT bError THEN
_bHasCreated := TRUE;
END_IF
nState_CreateDB := 0;
END_IF
END_CASE
CreateErrorLogDB := nState_CreateDB = 0;
AddErrorEntry (method)
The AddErrorEntry method can be used to write different messages into the database.
METHOD AddErrorEntry : BOOL
VAR_INPUT
tTimestamp : DT;
eSeverity : E_Severity;
nErrCode : UDINT;
sMessage : T_MaxString;
END_VAR
CASE nState_AddEntry OF
0:
ipResultEvt := fbPLCDBWrite.ipTcResult;
stError.tTimestamp := tTimestamp;
CASE eSeverity OF
TcEventSeverity.Info:
stError.sSeverity := 'Info';
TcEventSeverity.Warning:
stError.sSeverity := 'Warning';
TcEventSeverity.Verbose:
stError.sSeverity := 'Verbose';
TcEventSeverity.Critical:
stError.sSeverity := 'Critical';
TcEventSeverity.Error:
stError.sSeverity := 'Error';
END_CASE
stError.nErrCode := nErrCode;
stError.sMsg := sMessage;
arrColumns[0] := 'Timestamp';
arrColumns[1] := 'ErrorCode';
arrColumns[2] := 'Severity';
arrColumns[3] := 'Message';
nState_AddEntry := 1;
1:
IF fbPLCDBWrite.WriteStruct(
hDBID:= nDBID,
sTableName:= sTableName,
pRecord:= ADR(stError),
cbRecord:= SIZEOF(stError),
pColumnNames:= ADR(arrColumns),
cbColumnNames:= SIZEOF(arrColumns)) THEN
nState_AddEntry := 100;
END_IF
100:
IF _SetResultInfo(1033) THEN
nState_AddEntry := 0;
END_IF
END_CASE
AddErrorEntry := nState_AddEntry = 0;
ReadLastError (method)
The method ReadLastError can be used to read the latest (last) entry from the database.
METHOD ReadLastError : BOOL
VAR_OUTPUT
tTimestamp : DT;
sSeverity : STRING(10);
nErrCode : UDINT;
sMessage : T_MaxString;
END_VAR
CASE nState_ReadLastEntry OF
0:
ipResultEvt := fbPLCDBRead.ipTcResult;
arrColumns[0] := 'Timestamp';
arrColumns[1] := 'ErrorCode';
arrColumns[2] := 'Severity';
arrColumns[3] := 'Message';
nState_ReadLastEntry := 1;
1:
IF fbPLCDBRead.ReadStruct(
hDBID:= nDBID,
sTableName:= sTableName,
pColumnNames:= ADR(arrColumns),
cbColumnNames:= SIZEOF(arrColumns),
sOrderByColumn:= 'ID',
eOrderType:= E_OrderType.DESC,
nStartIndex:= 0,
nRecordCount:= 1,
pData:= ADR(stReadData),
cbData:= SIZEOF(stReadData)) THEN
nState_ReadLastEntry := 100;
END_IF
100:
IF _SetResultInfo(1033) THEN
IF NOT fbPLCDBRead.bError THEN
tTimestamp := stReadData.tTimestamp;
sSeverity := stReadData.sSeverity;
nErrCode := stReadData.nErrCode;
sMessage := stReadData.sMsg;
END_IF
nState_ReadLastEntry := 0;
END_IF
END_CASE
ReadLastError := nState_ReadLastEntry = 0;
GetErrorTimerange (method)
The method GetErrorTimerange can be used to read all messages from a particular interval.
METHOD GetErrorTimerange : BOOL
VAR_INPUT
tStartTimestamp : DT;
tEndTimestamp : DT;
nStartIndex : UDINT;
END_VAR
VAR_OUTPUT
nErrorCount: UDINT;
arrErrors : ARRAY [0..10] OF ST_ErrorEntry;
END_VAR
CASE nState_ErrorTimerange OF
0:
ipResultEvt := fbPLCDBRead.ipTcResult;
stSearchData.dtStartTimestamp := tStartTimestamp;
stSearchData.dtEndTimestamp := tEndTimestamp;
sCmd := 'SELECT Timestamp, ErrorCode, Severity, Message FROM
tbl_Errors WHERE Timestamp >= {start} AND Timestamp <= {end}';
arrParameter[0].sParaName := 'start';
arrParameter[0].eParaType := E_ExpParameterType.DateTime;
arrParameter[0].nParaSize := 4;
arrParameter[1].sParaName := 'end';
arrParameter[1].eParaType := E_ExpParameterType.DateTime;
arrParameter[1].nParaSize := 4;
nState_ErrorTimerange := 1;
1:
IF fbPLCDBCmd.ExecuteDataReturn(
hDBID:= nDBID,
pExpression:= ADR(sCmd),
cbExpression:= SIZEOF(sCmd),
pData:= ADR(stSearchData),
cbData:= SIZEOF(stSearchData),
pParameter:= ADR(arrParameter),
cbParameter:= SIZEOF(arrParameter),
nStartIndex:= nStartIndex,
nRecordCount:= 10,
pReturnData:= ADR(arrErrs),
cbReturnData:= SIZEOF(arrErrs),
pRecords:= ADR(nErrCount)) THEN
nState_ErrorTimerange := 100;
END_IF
100:
IF _SetResultInfo(1033) THEN
nErrorCount := nErrCount;
arrErrors := arrErrs;
nState_ErrorTimerange := 0;
END_IF
END_CASE
GetErrorTimerange := nState_ErrorTimerange = 0;
_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
EventSourcePath := ipResultEvt.ipSourceInfo.sName;
EventId := ipResultEvt.nEventId;
bError := (ipResultEvt.eSeverity = TcEventSeverity.Error) OR
(ipResultEvt.eSeverity = TcEventSeverity.Critical);
nState_SetResInfo:=0;
_SetResultInfo := TRUE;
END_IF
END_CASE