Message Logger
In diesem Szenario wird der PLC Expert Mode beispielhaft für einen Message Logger in der SPS gezeigt. In dem Beispielprogramm wird mit den Funktionsbausteinen des TwinCAT Database Servers ein Funktionsbaustein erstellt, welcher verschiedene Methoden zum Erzeugen und Auslesen von Meldungen bereitstellt. Die Datenbank, in der die Meldungen abgelegt werden, wird aus der SPS heraus erzeugt. Im MAIN-Programm wird eine beispielhafte Verwendung des erzeugten Bausteins implementiert. Alle 7 Tage wird eine neue Datenbankdatei erzeugt. Drei verschiedene Meldungen können gesendet werden. Zusätzlich besteht die Möglichkeit die letzte Meldung bzw. alle Meldungen aus einem bestimmten Zeitraum abzurufen.

Kategorie | PLC Expert Mode |
Verwendete Datenbank | |
Kompatible Datenbanken | Mit kleineren Anpassungen für alle unterstützten Datenbanktypen anwendbar |
Verwendete SPS Funktionsbausteine | FB_PLCDBCreateEvt, FB_PLCDBCmdEvt, FB_PLCDBWriteEvt, FB_PLCDBReadEvt |
Verwendete SPS Bibliotheken | Tc3_Database, Tc3_Eventlogger |
Download |
FB_ErrorLogger
CreateErrorLogDB (Methode)
Die Methode CreateErrorLogDB erzeugt eine MS-Compact-Datenbankdatei und erstellt die Tabelle, in die die Meldungen abgespeichert werden.
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 (Methode)
Mit der Methode AddErrorEntry können verschiedene Meldungen in die Datenbank geschrieben werden.
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 (Methode)
Mit der Methode ReadLastError kann der aktuellste (letzte) Eintrag aus der Datenbank ausgelesen werden.
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 (Methode)
Wenn alle Meldungen eines bestimmten Zeitraums ausgelesen werden sollen, kann dies mit der Methode GetErrorTimerange erfolgen.
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 Methode)
In der privaten Methode _SetResultInfo wird das Nachrichten Interface I_Message vom TwinCAT Eventlogger ausgewertet.
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