Alarmlogging-Filter wieder herstellen

Zunächst muss natürlich erst ein passender Filter im Alarmlogging – Fenster in der Runtime erstellt werden.

Anschließend wird mit den Windows-Explorer die Datei „CCAlarmFilterStorage.xml“ kopiert und dann umbenannt. Diese Datei befindet sich im Projektverzeichnis im Unterordner ”MELD“. In den Beispiel nachfolgenden  Listing  habe ich diese Datei in ”CCAlarmFilterStorage.xxx“ umbenannt. Die Frage Umbenennen der Dateinamenerweiterung einfach mit ja bestätigen und schon ist eine Datei für die Werkseinstellung vorhanden. Anschließend muss noch das nachfolgende Script an einen Button (Klick – Ereignis) gebunden werden.


#include "apdefap.h"
void OnClick(char* lpszPictureName, char* lpszObjectName, char* lpszPropertyName)
{
#pragma code ("Kernel32.dll")
  BOOL CopyFileA(  LPCTSTR lpExistingFileName,  LPCTSTR lpNewFileName,  BOOL bFailIfExists);
#pragma code ()
char path[255], srcFile[255], desFile[255];
CMN_ERROR er;
DM_DIRECTORY_INFO info;
BOOL rt;

memset(path, 0, sizeof(path));
memset(srcFile, 0, sizeof(srcFile));
memset(desFile, 0, sizeof(desFile));
memset(&er, 0, sizeof(CMN_ERROR));
memset(&info, 0, sizeof(DM_DIRECTORY_INFO));

if(DMGetRuntimeProject(path, sizeof(path), &er))   //Runtimeproject abrufen
{
  if(DMGetProjectDirectory("bla", path, &info, &er))   //Projektpfad ermitteln
  { 
   sprintf(srcFile, "%s\\MELD\\CCAlarmFilterStorage.xxx", info.szProjectDir);
   sprintf(desFile, "%s\\MELD\\CCAlarmFilterStorage.xml", info.szProjectDir);
   rt = CopyFileA(srcFile, desFile, FALSE);
  }
 }
}

Funktionsbeschreibung: Bei Buttonklick wird zunächst das aktuell laufende WinCC-Projekt ermittelt. Daraufhin wird das Projektverzeichnis abgerufen. Nun wird für die Quell- und Zieldatei der absolute Dateipfad erstellt und die vorher umbenannte Datei (srcFile) kopiert und die „alte“ Filterdatei (desFile) damit überschrieben.

HINWEIS!  Die Funktion „CopyFileA“ ist eine mit #pragma Code.. importierte Funktion. Der Rückgabewert ist TRUE wenn erfolgreich kopiert wurde.

Bit in einen Byte setzen

Wie auch beim Bit prüfen stehen auch beim Setzen einzelner Bits verschiedene Methoden zur Verfügung. Erst möchte ich die Inline-Variante aufzeigen. Beim Setzen eines Bits muss lediglich das Byte mit der Bitmaske (hier 0000 0100) „verodert“ werden.

//Bitnummer 2 setzen
int x = 0x9;         // Bitmuster 0000 1001
x = x | 0x4;         // gesetzt weil 0x4 -> 0000 0100

Beim Zurücksetzen (löschen) eines Bits muss die Bitmaske negiert werden um dann mit dem Byte „verundet“ zu werden. Klingt seltsam – ist es aber nicht.

//Bitnummer 2 löschen
int x = 0xd;         // Bitmuster 0000 1101
x = x & (~0x4);      // gelöscht weil ~0x4 -> 1111 1011

Natürlich besteht auch hier die Möglichkeit das Ganze in eine Funktion zu packen. Das Ergebnis einer Schiebe-Operation ist in der Regel ein int. Deshalb auch der Cast in ein BYTE um die Compiler-Warnungen zu unterbinden.

//Bit setzen / löschen
BYTE SetBit(BYTE data, BYTE Bit, BOOL value)
{
  BYTE mask = (BYTE)(0x1 << Bit);
  if(value == TRUE)
    return (BYTE)(data | mask);
  else
    return (BYTE)(data & (~mask));
}

So wird die neue Funktion verwendet

BYTE x = 0x9;               // Bitmuster 0000 1001
x = SetBit(x, 2, TRUE);    // x = 0000 1101
x = SetBit(x, 3, FALSE);   // x = 0000 0101

Bit in einen Byte testen

Manchmal ist es nötig ein Bit in einen Byte oder Word zu prüfen ob gesetzt oder nicht. für diesen Zweck gibt es verschiedene Ansätze die ich nachfolgend aufzeichnen möchte.

eine Variante ist inline den Wert mit Bitoperationen zu prüfen

//Bitnummer 3 testen
int x = 0x9;         // Bitmuster 0000 1001

if((x & 0x8) > 0)    // TRUE weil 0x8 -> 0000 1000

eine weitere Variante ist das erstellen einer WinCC Funktion. Das Ergebnis einer Schiebe-Operation ist in der Regel ein int. Deshalb auch der Cast in ein BYTE um die Compiler-Warnungen zu unterbinden.

BOOL GetBit(BYTE data, BYTE bit)
{
   BYTE pattern = (BYTE)(0x1 << bit);
   if((data & pattern) > 0)
     return TRUE;
   return FALSE;
}

Das gleiche Beispiel wie oben bei Verwendung der Funktion GetBit. So ist das meines Erachtens lesbarer.

//Bitnummer 3 testen
int x = 0x9;         // Bitmuster 0000 1001

if(GetBit(x, 3))    // TRUE weil 0x8 -> 0000 1000

Die Funktion GetBit kann auch für ein WORD oder DWORD abgeändert werden. Zu beachten ist dann dass die Bitnummern nur dann verwendet werden können wenn die Variablen auch SPS-seitig so definiert sind. Sind das hingegen  SPS-seitig nur einzelne Bits muss die Bytereichenfolge beachtet werden.

noch ein Beispiel:

Variable vom Type WORD -> MW10 (SPS-Seitig Ab M10.0 bis M11.7 16 einzelne Bits)
soll das Bit M10.0 getestet werden muss die Bitnummer 8 verwendet werden.

Operatoren

Hier sind die in WinCC verfügbaren Operatoren aufgelistet (ohne Anspruch auf Vollständigkeit). Bei Wikibooks.org gibt es auch eine schöne Beschreibung aller Operanden.

  • Arithmetische Operationen (+ – * / %)
  • Zuweisungs Operatoren (++ — =)
  • Kombinierte Zuweisungsoperatoren (+= -= *= /= %= &=  |=….)
  • Vergleichsoperationen (== != <= >= < >)
  • Logikoperatoren (&& || !)
  • Bitmanipulationen (& | ^ ~ << >>)
  • Sonstige (. -> & ())

In den nachfolgenden Beispielen werde ich die Nutzung der häufigsten Operatoren zeigen.

Zuerst die arithmetische Operationen

int i = 5;    // i hat den Wert 5
int x = i + 3 // x hat den Wert 8
int y = x / 2 // y hat den Wert 4
int z = x - 3 // z hat den Wert 5 

hier noch die verschiedenen Zuweisungsoperatoren

int i = 5;  // i hat den Wert 5
i++;        // i hat den Wert 6
i--;        // i hat den Wert 5

ein paar kombinierte Operatoren

int i = 0, a = 0, b = 0;
i += 5;         // i hat den Wert 5 -> i = i + 5 
i /= 2;         // i hat den Wert 2 -> i = i / 2
i *= 5;         // i hat den Wert 10 -> i = i * 5
i -= 5;         // i hat den Wert 5 -> i = i - 5 

noch ein nützliche Bitoperationen

x = 5;          //x ist 0000 0101 (5)
y = x << 1;     //y ist 0000 1010 (10)
z = y && 0x3;   //z ist 0000 0010 (2)
z = x || 0x3;   //z ist 0000 0111 (7)
z = z >> 2;     //z ist 0000 0001 (1)
z = ~x;         //z ist 1111 1010 (250)

zu guter Letzt noch das Vergleichen

y > 9           //TRUE y = 10
y < 9           //FALSE y = 10
y >= x          //TRUE y = 10 >= x = 5 
y <= x          //FALSE y = 10 >= x = 5
y == 10         //TRUE y = 10
y != x          //FALSE 

(y >= 5) && (y <= 15)  //TRUE y im Bereich zwischen 5 und 15
(y >= 5) || (y <= 15)  //TRUE immer - das ist Käse
!((y >= 5) && (y <= 15))  //FALSE weil negiert

Grundlegendes zum Prüfen von Bedingungen

Natürlich ist in WinCC auch das Auswerten von Daten mit if – elseif – else oder mit switch – case möglich.
Zunächst ein Script mit if – else. Als Ergebnis wird immer „ansonsten mach was anderes“ ausgegeben.


int i = 0;
if( i == 1 )
{
  printf("ich mach was wenn i = 1\r\n");
}
else
{
  printf("ansonsten mach was anderes\r\n");
}

Das nächste Script zeigt eine Switch – Case Anweisung. Das einzige was hier beachtet werden muss ist dass es sich nur um sogenannte Einsprung-Marken handelt. Ohne den break würden alle nachfolgenden Anweisung auch noch durch gearbeitet werden. Auch hier ist das Ergebnis immer „ansonsten mach was anderes“.


int i = 0;
switch(i)
{
  case 1:
  printf("ich mach was wenn i = 1\r\n");
  break;
  case 2:
  printf("ich mach was wenn i = 2\r\n");
  break;
  default:
  printf("ansonsten mach was anderes\r\n");
  break;
};

Grundlegendes zu Schleifen

Erstmal vorweg – ich werde hier nicht jedes Detail von C „breittreten“. Es gibt im Netz viele sehr gute Webseiten die die verfügbaren C-Funktionen ausführlich erklären. Die Webseite cplusplus ist mein persönlicher Favorit.

In WinCC werden die C-Scripte in verschiedene Kategorien eingeteilt

  1. Aktionen – getriggerte  in Hintergrund ablaufende Scripte. Müssen einen Wert zurück geben!
  2. Funktionen – zu einem Modul / Funktion zusammengefasste Scripte
  3. Ereignisse – durch Ereignisse ausgelöste Scripte

Das nachfolgende einfache Beispiel gibt 10 Zeilen in das Ausgabefenster apdiag aus (printf).


int i = 0;
for (i = 0; i < 10; i++)
{
  printf("schlichte Ausgabe: %d\r\n", i);
}

Die Do – while oder die while – Schleife geben wie auch die for – Schleife 10 Zeilen aus. Bei der do – while – Schleife wird die Schleife erst durchlaufen bevor die Bedingung überprüft wird. Anders dagegen die while – Schleife, da wird vor dem Durchlaufen die Bedingung überprüft.


int i = 0;
do
{
  printf("schlichte Ausgabe: %d\r\n", i);
  i++;
}while(i < 10);

while(i < 10)
{
  printf("schlichte Ausgabe: %d\r\n", i);
  i++;
}

C-Scripte

C-Scripte können sowohl in den Graphics-Designer als auch im Global-Script verwendet werden. Das im WinCC verwendete C basiert auf ANSI-C. Jeder der bei C an eine Entwicklungsumgebung wie Visual Studio denkt wird da herb enttäuscht. So etwas wie einen Projektexplorer oder eine Klassenansicht fehlt ebenso wie vernünftiges Debugging-Tool. Die einzige Möglichkeit zum debugging ist ein schlichtes „printf“ das Informationen an das Augabefenster von „apdiag“ sendet.

Ich werden in den künftigen Beiträgen zunächst mit ein paar Grundlagen posten und dann verschiedene Problemlösungen anhand von paar Beispiele zeigen.