CodeGenerator for PLC´s (DE)
Der Codegenerator for PLC´s ist ein kleines Programm das beim erstellen von neuen Funktionsbausteinen auf einer SPS helfen soll. Es erzeugt das Grundgerüst für den jeweiligen FB inklusive Datentypen, Variablen usw. Der grösste Nutzen des Programmes ist es aber das die Funktionsaufrufe auf Basis eine Excel Files definiert werden können und diese dann vollautomatisch in der Richtigen Syntax und der richtigen Struktur für die jeweilige SPS erzeugt wird.
Workflow:
- Daten/Schnittstellen in Structure.xlsx erfassen
- Parmeter eingeben
- CodeGenerator starten
- Erzeugte Quellen ins Projekt kopieren/importieren
- Kaffe Trinken !
Zielsetzung
- Schnelles erzeugen von Funktionsbausteinen(FB)
- Schnelle und Fehlerfreie Beschaltung der FB Aufrufe
- Offen für neue Sprach/SPS Generatoren
Technik
Der CodeGenerator ist in der Sprache Python 3 geschrieben. Dadurch ist das Programm auf alle Betriebsystem(Linux, Windows, MacOS) grundsätzlich lauffähig. Jedoch wurde der CodeGenerator Primär für Linux und Windows entwickelt und auch getestet.
Unterstütze Sprachen/Steuerungen
- B&R Automation Studio 4.x.x
- Structured Text (ST EN 61131-3)
- C++ (CPP) in Entwicklung
- Siemens TIA_V15
- Structured Text (SCL)
Unterstütze Zielplatformen
- Linux
- Ubuntu 16.04
- Ubuntu 18.04
- Windows 7, 10
GUI Gooey
Das User Interface wird mittels eine genialen Python Bibliothek namens Gooey von Chris Kiehl realisiert. Die Bibliothek schafft ein einfaches User Interface für jedes Kommandozeilenprogramm, und basiert auf dem GUI Toolkit wxPython, und dient als Basis für den CodeGenerator
Verwendete Python3 Bibliotheken
Structure.xlsx
In der Datei Structure.xlsx werden alle Informationen für den Funktionsbaustein erfasst und hinterlegt. Aus den Enthalten Informationen werden die Quellen erzeugt.
Objects
Hier werden alle Objektinstanzen angegeben die benötigt werden.
- Spalte A: Hier wird der Name der Instanz angegeben (Name der Spalte darf nicht verändert werden)
- Spalte B: Hier wird der Name der Funktion angegeben (Name der Spalte darf nicht verändert werden)
- Spalte C: Enthält die Beschreibung der Objektinstanz (Name der Spalte darf nicht verändert werden)
- Spalte D: Hier wird das BMK (Betriebsmittelkennzeichen) angegeben (Name der Spalte darf nicht verändert werden)
- Spalte E-xx: Sind für die Parameter des Funktionsbausteines.
Achtung ! Die Spalten Instanzname, Functionname, Description werden auf Sonderzeichen und die Länge geprüft. Fehler werden im Ausgabefenster ausgegeben.
Die Spalten ab E werden keiner Prüfung mehr unterzogen und werden 1:1 in die Quelldatei weitergeben, um bei der Beschaltung so flexibel wie möglich zu sein.
Zusätzlich müssen alle Parameter von VAR_INPUT, VAR_OUTPUT, VARINOUT in diese Tabelle kopiert werden.
Es ist wichtig das die Parameter gleich bennant werden, wie sie in den Tabellen VAR_INPUT, VAR_OUTPUT, VARINOUT deklariert worden sind.
VAR_INPUT/OUTPUT/INOUT
In diesen 3 Tabellen wird die Schnittstelle(Interface) des Bausteins definiert.
Achtung ! Die Spalten Name, Datatyp, Description werden auf Sonderzeichen,Länge und erlaubte Datentypen geprüft. Fehler werden im Ausgabefenster ausgegeben.
CTRL/STS/PRM
In diesen 3 Tabellen werden die Types CTRL,STS,PRM definiert.
Achtung ! Die Spalten Name, Datatyp, Description werden auf Sonderzeichen,Länge und erlaubte Datentypen geprüft. Fehler werden im Ausgabefenster ausgegeben.
Erlaubte Datentypen
Die folgenden Datentypen sind hinterlegt und werden nicht als Fehler ausgewertet:
plcTypes = (
'BOOL',
'BYTE',
'UINT',
'SINT',
'INT',
'UDINT',
'DINT',
'WORD',
'DWORD',
'REAL',
'TIME',
)
Ungültige Sonderzeichen
Folgende Sonderzeichen sind nicht erlaubt in erzeugen einen Fehler im Meldefenster:
invalidCharacters = (
'ä',
'Ä',
'ö',
'Ö',
'Ü',
'ü',
'$',
'&',
)
Erste Schritte
- Pfad des Structure.xlsx auswählen (data_directory)
- Pfad für die Ausgabe der Quelldateien angeben (output_directory)
- Ziel SPS auswählen B&R oder Siemens (target_plc)
- Zielsprache auswählen (target_lang)
- Version der Entwicklungsumgebung auswählen (target_ide)
- Author angeben der im Kopf der erzeugten Quellen stehen soll (author)
- Start Drücken
- Im Ausgabefenster werden Info und Fehlermeldungen ausgeben
Die erzeugten Quellen sollten sich jetzt im Zielverzeichnis befinden.
Codegenerator für B&R
Die erzeugten Quellen für die B&R Steuerungen müssen mittels Copy&Paste in die zugehöringen Programmodule kopiert werden. Hierzu werden die betroffene Module als Text geöffnet.
- Modul als Text öffnen
- Kopieren des Codes von den erzeugten Quellen
- Fertig
Der Import/Export von kompletten Modulen wird noch nicht unterstützt.
Generierte Quellen:
Die Quellen werden in folgender Form erstellt:
.
├── FB_Std.fun
├── FB_Std_lib.st
├── FB_Std.st
├── FB_Std.typ
└── FB_Std.var
Datei: FB_Std.fun
FUNCTION_BLOCK FB_Std
VAR_INPUT
IN_Prm_0 : BOOL; (*Input Parameter 1*)
IN_Prm_1 : BOOL; (*Input Parameter 2*)
IN_Prm_2 : BOOL; (*Input Parameter 3*)
IN_Prm_3 : BOOL; (*Input Parameter 4*)
IN_Prm_4 : BOOL; (*Input Parameter 5*)
END_VAR
VAR_OUTPUT
OUT_Prm_0 : BOOL; (*Output Parameter 1*)
OUT_Prm_1 : BOOL; (*Output Parameter 2*)
OUT_Prm_2 : BOOL; (*Output Parameter 3*)
OUT_Prm_3 : BOOL; (*Output Parameter 4*)
OUT_Prm_4 : BOOL; (*Output Parameter 5*)
END_VAR
VAR_IN_OUT
Object_struct : TYP_FB_Std; (*Objectstrucuture*)
END_VAR
END_FUNCTION_BLOCK
Datei: FB_Std.st
//***********************************************
// Codegenerator BuR V0.9.0
// by dgrill
// http://www.dgrill.at
// dgrill@dgrill.at
// Date of generation: 15.12.2018 13:07
//***********************************************
//***********************************************
// Standard FB FB1
//***********************************************
Object1(
IN_Prm_0 := "Prm0",
IN_Prm_1 := "Prm1",
IN_Prm_2 := "Prm2",
IN_Prm_3 := "Prm3",
IN_Prm_4 := "Prm4",
Object_struct := "DB_FB_Std".Object1);
"Prm5" := Object1.OUT_Prm_0;
"Prm6" := Object1.OUT_Prm_1;
"Prm7" := Object1.OUT_Prm_2;
"Prm8" := Object1.OUT_Prm_3;
"Prm9" := Object1.OUT_Prm_4;
//***********************************************
// Standard FB FB2
//***********************************************
Object2(
IN_Prm_0 := "Prm0",
IN_Prm_1 := "Prm1",
IN_Prm_2 := "Prm2",
IN_Prm_3 := "Prm3",
IN_Prm_4 := "Prm4",
Object_struct := "DB_FB_Std".Object2);
"Prm5" := Object2.OUT_Prm_0;
"Prm6" := Object2.OUT_Prm_1;
"Prm7" := Object2.OUT_Prm_2;
"Prm8" := Object2.OUT_Prm_3;
"Prm9" := Object2.OUT_Prm_4;
//***********************************************
// Standard FB FB3
//***********************************************
Object3(
IN_Prm_0 := "Prm0",
IN_Prm_1 := "Prm1",
IN_Prm_2 := "Prm2",
IN_Prm_3 := "Prm3",
IN_Prm_4 := "Prm4",
Object_struct := "DB_FB_Std".Object3);
"Prm5" := Object3.OUT_Prm_0;
"Prm6" := Object3.OUT_Prm_1;
"Prm7" := Object3.OUT_Prm_2;
"Prm8" := Object3.OUT_Prm_3;
"Prm9" := Object3.OUT_Prm_4;
Ausgabe wurde gekürzt
Datei: FB_Std.typ
TYPE
TYP_FB_Std : STRUCT
CTRL :
Datei: FB_Std.typ FB_Std_CTRL;
STS : FB_Std_STS;
PRM : FB_Std_PRM;
END_STRUCT;
FB_Std_CTRL : STRUCT
Dummy : BOOL; (*Dummy*)
END_STRUCT;
FB_Std_STS : STRUCT
Dummy : BOOL; (*Dummy*)
END_STRUCT;
FB_Std_PRM : STRUCT
Dummy : REAL; (*Dummy*)
END_STRUCT;
END_TYPE
Datei: FB_Std.var
VAR
Object1 : FB_Std; (*Standard FB*)
Object2 : FB_Std; (*Standard FB*)
Object3 : FB_Std; (*Standard FB*)
Object4 : FB_Std; (*Standard FB*)
Object5 : FB_Std; (*Standard FB*)
Object6 : FB_Std; (*Standard FB*)
Object7 : FB_Std; (*Standard FB*)
Object8 : FB_Std; (*Standard FB*)
Object9 : FB_Std; (*Standard FB*)
Object10 : FB_Std; (*Standard FB*)
END_VAR
Datei: FB_Std.typ
TYPE
TYP_FB_Std : STRUCT
CTRL :
Datei: FB_Std.typ FB_Std_CTRL;
STS : FB_Std_STS;
PRM : FB_Std_PRM;
END_STRUCT;
FB_Std_CTRL : STRUCT
Dummy : BOOL; (*Dummy*)
END_STRUCT;
FB_Std_STS : STRUCT
Dummy : BOOL; (*Dummy*)
END_STRUCT;
FB_Std_PRM : STRUCT
Dummy : REAL; (*Dummy*)
END_STRUCT;
END_TYPE
Datei: FB_Std_lib.st
//***********************************************
// FB_Std
// Author: dgrill
// Version: 1.0
// Date: 15.12.2018 13:07
// Description:
//
// Interface:
// VAR_INPUT:
// IN_Prm_0: BOOL Input Parameter 1
// IN_Prm_1: BOOL Input Parameter 2
// IN_Prm_2: BOOL Input Parameter 3
// IN_Prm_3: BOOL Input Parameter 4
// IN_Prm_4: BOOL Input Parameter 5
//
// VAR_OUTPUT:
// OUT_Prm_0: BOOL Output Parameter 1
// OUT_Prm_1: BOOL Output Parameter 2
// OUT_Prm_2: BOOL Output Parameter 3
// OUT_Prm_3: BOOL Output Parameter 4
// OUT_Prm_4: BOOL Output Parameter 5
//
// VAR_IN_OUT:
// Object_struct: TYP_FB_Std Objectstrucuture
//
// Rev:
//
//***********************************************
FUNCTION_BLOCK FB_Std
// TODO - Insert Code here
END_FUNCTION_BLOCK
Codegenerator für Siemens
- Quelle ins TIA Portal importieren
- Bausteine aus Quelle generieren
- Fertig
Generierte Quelle:
Die Quellen werden in folgender Form erstellt:
Datei: FB_Std.scl
TYPE "FB_Std_CTRL"
VERSION : 1.0
STRUCT
Dummy : BOOL; //Dummy
END_STRUCT;
END_TYPE
TYPE "FB_Std_CTRL"
VERSION : 1.0
STRUCT
Dummy : BOOL; //Dummy
END_STRUCT;
END_TYPE
TYPE "FB_Std_CTRL"
VERSION : 1.0
STRUCT
Dummy : REAL; //Dummy
END_STRUCT;
END_TYPE
TYPE "TYP_FB_Std"
VERSION : 1.0
STRUCT
CTRL : FB_Std_CTRL;
STS : FB_Std_STS;
PRM : FB_Std_PRM;
END_STRUCT;
END_TYPE
FUNCTION_BLOCK "FB_Std"
{ S7_Optimized_Access := 'TRUE' }
AUTHOR : dgrill
Version : 1.0
VAR_INPUT
IN_Prm_0 { ExternalAccessible := 'False'; ExternalVisible := 'False'; ExternalWritable := 'False'} : BOOL; //Input Parameter 1
IN_Prm_1 { ExternalAccessible := 'False'; ExternalVisible := 'False'; ExternalWritable := 'False'} : BOOL; //Input Parameter 2
IN_Prm_2 { ExternalAccessible := 'False'; ExternalVisible := 'False'; ExternalWritable := 'False'} : BOOL; //Input Parameter 3
IN_Prm_3 { ExternalAccessible := 'False'; ExternalVisible := 'False'; ExternalWritable := 'False'} : BOOL; //Input Parameter 4
IN_Prm_4 { ExternalAccessible := 'False'; ExternalVisible := 'False'; ExternalWritable := 'False'} : BOOL; //Input Parameter 5
END_VAR
VAR_OUTPUT
OUT_Prm_0 { ExternalAccessible := 'False'; ExternalVisible := 'False'; ExternalWritable := 'False'} : BOOL; //Output Parameter 1
OUT_Prm_1 { ExternalAccessible := 'False'; ExternalVisible := 'False'; ExternalWritable := 'False'} : BOOL; //Output Parameter 2
OUT_Prm_2 { ExternalAccessible := 'False'; ExternalVisible := 'False'; ExternalWritable := 'False'} : BOOL; //Output Parameter 3
OUT_Prm_3 { ExternalAccessible := 'False'; ExternalVisible := 'False'; ExternalWritable := 'False'} : BOOL; //Output Parameter 4
OUT_Prm_4 { ExternalAccessible := 'False'; ExternalVisible := 'False'; ExternalWritable := 'False'} : BOOL; //Output Parameter 5
END_VAR
VAR_IN_OUT
Object_struct { ExternalAccessible := 'False'; ExternalVisible := 'False'; ExternalWritable := 'False'} : TYP_FB_Std; //Objectstrucuture
END_VAR
BEGIN
//***********************************************
// FB_Std
// Author: dgrill
// Version: 1.0
// Date: 15.12.2018 13:07
// Description:
//
// Rev:
//
//***********************************************
// TODO - Insert Code here
END_FUNCTION_BLOCK
DATA_BLOCK "DB_FB_Std"{ S7_Optimized_Access := 'TRUE' }
AUTHOR : user
Version : 1.0
VAR
"Object1" : "TYP_FB_Std"; // Standard FB
"Object2" : "TYP_FB_Std"; // Standard FB
"Object3" : "TYP_FB_Std"; // Standard FB
"Object4" : "TYP_FB_Std"; // Standard FB
"Object5" : "TYP_FB_Std"; // Standard FB
"Object6" : "TYP_FB_Std"; // Standard FB
"Object7" : "TYP_FB_Std"; // Standard FB
"Object8" : "TYP_FB_Std"; // Standard FB
"Object9" : "TYP_FB_Std"; // Standard FB
"Object10" : "TYP_FB_Std"; // Standard FB
END_VAR
BEGIN
END_DATA_BLOCK
FUNCTION_BLOCK "Call_FB_Std"
{ S7_Optimized_Access := 'TRUE' }
AUTHOR : user
Version : 1.0
VAR
I_FB_Std { ExternalAccessible := 'False'; ExternalVisible := 'False'; ExternalWritable := 'False'}: Array[0..10] of "FB_Std";
END_VAR
BEGIN
//***********************************************
// Codegenerator Siemens V0.9.0
// by dgrill
// http://www.dgrill.at
// dgrill@dgrill.at
// Date of generation: 15.12.2018 13:07
//***********************************************
REGION Standard FB FB1
#I_FB_Std[0](
IN_Prm_0 := "Prm0",
IN_Prm_1 := "Prm1",
IN_Prm_2 := "Prm2",
IN_Prm_3 := "Prm3",
IN_Prm_4 := "Prm4",
OUT_Prm_0 => "Prm5",
OUT_Prm_1 => "Prm6",
OUT_Prm_2 => "Prm7",
OUT_Prm_3 => "Prm8",
OUT_Prm_4 => "Prm9",
Object_struct := "DB_FB_Std".Object1);
END_REGION
REGION Standard FB FB2
#I_FB_Std[1](
IN_Prm_0 := "Prm0",
IN_Prm_1 := "Prm1",
IN_Prm_2 := "Prm2",
IN_Prm_3 := "Prm3",
IN_Prm_4 := "Prm4",
OUT_Prm_0 => "Prm5",
OUT_Prm_1 => "Prm6",
OUT_Prm_2 => "Prm7",
OUT_Prm_3 => "Prm8",
OUT_Prm_4 => "Prm9",
Object_struct := "DB_FB_Std".Object2);
END_REGION
REGION Standard FB FB3
#I_FB_Std[2](
IN_Prm_0 := "Prm0",
IN_Prm_1 := "Prm1",
IN_Prm_2 := "Prm2",
IN_Prm_3 := "Prm3",
IN_Prm_4 := "Prm4",
OUT_Prm_0 => "Prm5",
OUT_Prm_1 => "Prm6",
OUT_Prm_2 => "Prm7",
OUT_Prm_3 => "Prm8",
OUT_Prm_4 => "Prm9",
Object_struct := "DB_FB_Std".Object3);
END_REGION
REGION Standard FB FB4
#I_FB_Std[3](
IN_Prm_0 := "Prm0",
IN_Prm_1 := "Prm1",
IN_Prm_2 := "Prm2",
IN_Prm_3 := "Prm3",
IN_Prm_4 := "Prm4",
OUT_Prm_0 => "Prm5",
OUT_Prm_1 => "Prm6",
OUT_Prm_2 => "Prm7",
OUT_Prm_3 => "Prm8",
OUT_Prm_4 => "Prm9",
Object_struct := "DB_FB_Std".Object4);
END_REGION
Ausgabe wurde gekürzt
END_FUNCTION_BLOCK
Projektstruktur
.
├── build.spec
├── CodeGenerator
│ ├── conf
│ │ ├── config.py
│ │ └── __init__.py
│ ├── generators
│ │ ├── BaseGenerator.py
│ │ ├── Generator_BuR.py
│ │ ├── Generator_SIE.py
│ │ ├── __init__.py
│ │ └── Syntax.py
│ ├── images
│ │ ├── config_icon.png
│ │ └── program_icon.ico
│ ├── __init__.py
│ └── parser
│ ├── Checks.py
│ └── Spreadsheet.py
├── data
│ ├── BuR
│ │ ├── FB_Std.fun
│ │ ├── FB_Std_lib.st
│ │ ├── FB_Std.st
│ │ ├── FB_Std.typ
│ │ └── FB_Std.var
│ ├── SIE
│ │ └── FB_Std.scl
│ └── Template_structure.xlsx
├── doc
│ └── img
│ ├── CodeGen_BuR.png
│ └── CodeGen_SIE.png
├── LICENSE.txt
├── main.py
├── README.md
└── requirements.txt
build.spec
In der build.spec sind alle notwendigen Informationen enthalten um den source code mittels pyinstaller zu erstellen.
data
In diesem Verzeichnis befindet sich das Template für die Definitions Datei (Strucuture.xlsx), und die daraus erzeugten Quellen.
doc
In diesem Verzeichnis befinden sich alle notwendigen Dateien für das README.md File.
CodeGenerator
Ablauf des Programmes:
- main.py
Hier werden alle Konfiguration eingelesen und der zu startende Generator ausgewählt. - parser.Spreadsheet.py
Es werden die Daten vom Excel File eingelesen. - parser.Checks.py
Die eingelesenen Daten werden überprüft, im Fehlerfall werden Meldungen im Ausgabefenster ausgegeben. - generators.Generator_xxx.py
Der ausgewählte Generator wird gestartet und erzeugt die Quelldateien für das ausgewählte Zielsystem.
├── CodeGenerator
│ ├── conf
│ │ ├── config.py
│ │ └── __init__.py
│ ├── generators
│ │ ├── BaseGenerator.py
│ │ ├── Generator_BuR.py
│ │ ├── Generator_SIE.py
│ │ ├── __init__.py
│ │ └── Syntax.py
│ ├── images
│ │ ├── config_icon.png
│ │ └── program_icon.ico
│ ├── __init__.py
│ └── parser
│ ├── Checks.py
│ └── Spreadsheet.py
conf
Hier befindet sich die Konfigurationsdatei für das Programm.
generators
In diesem Verzeichnis befinden sich die Generatoren für das jeweilige Zielsystem. In der Quelle Syntax.py sind alle Sprachelemente der Zielsprache hinterlegt.
images
Hier befinden sich die Icons für das Programm.
parser
In diesem Verzeichnis befindt sich der Parser für das Excel Sheet und auch die Klasse zur Überprüfung der Daten.
Geplante Features
- Generator für C++ Code für B&R Steuerungen Q1/2019
- Direkter Import/Export für B&R Steuerungen Q1/2019
- Generator für Codesys Zielsysteme Q2/2019
Software Download
CodeGenerator für Linux und Windows:
CodeGenerator_BETA_V0.9.0
Source Code CodeGenerator:
Github CodeGenerator