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.

image-center

Workflow:

  1. Daten/Schnittstellen in Structure.xlsx erfassen
  2. Parmeter eingeben
  3. CodeGenerator starten
  4. Erzeugte Quellen ins Projekt kopieren/importieren
  5. Kaffe Trinken !
    pdf

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

placeholder image 1 placeholder image 2 placeholder image 3
Click to enlarge

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.

pdf Structure.xlsx

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.

image-center

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.

image-center

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.

image-center

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

  1. Pfad des Structure.xlsx auswählen (data_directory)
  2. Pfad für die Ausgabe der Quelldateien angeben (output_directory)
  3. Ziel SPS auswählen B&R oder Siemens (target_plc)
  4. Zielsprache auswählen (target_lang)
  5. Version der Entwicklungsumgebung auswählen (target_ide)
  6. Author angeben der im Kopf der erzeugten Quellen stehen soll (author)
  7. Start Drücken image-center
  8. Im Ausgabefenster werden Info und Fehlermeldungen ausgeben image-center

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.

  1. Modul als Text öffnen image-center
  2. Kopieren des Codes von den erzeugten Quellen image-center
  3. 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

  1. Quelle ins TIA Portal importieren
  2. Bausteine aus Quelle generieren image-center
  3. Fertig image-center

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:

  1. main.py
    Hier werden alle Konfiguration eingelesen und der zu startende Generator ausgewählt.
  2. parser.Spreadsheet.py
    Es werden die Daten vom Excel File eingelesen.
  3. parser.Checks.py
    Die eingelesenen Daten werden überprüft, im Fehlerfall werden Meldungen im Ausgabefenster ausgegeben.
  4. 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