68
Simulink objektorientiert mit C-Kernfunktionen - Anleitung mit Demo- / Test-Version Dr.-Ing. Hartmut Schorrig 3. Januar 2019 Zusammenfassung Dieser Artikel stellt Prinzipien dar und ist eine Anleitung für Generierung von Sfuncti- ons in Simulink unter Nutzung von Kern-Funktionalitäten in C. Die Generierung wird aus Informationen in den C-Headerfiles gesteuert. Es sind wenig zusätzliche Auf- wendungen in Scripts notwendig. Der Artikel ist gültig zusammen mit dem File Example_ObjO.zip. Dieses File enthält ein Beispielmodell, die Sources der Sfunctions, die entsprechenden Generierscripts und das Inspector-Tool. Die Zielgruppe für diesen Artikel und die hier vorgestellte Technologie sind Embedded- C-Entwickler, die entweder Simulink noch nicht kennen oder Simulink-Entwickler, die an C orientiert sind und gleichzeitig die Objektorientierte Programmierung im Blick haben. 1

Simulink objektorientiert mit C-Kernfunktionen - Anleitung mit Demo- / Test-Version · 2019. 1. 2. · Simulink objektorientiert mit C-Kernfunktionen - Anleitung mit Demo- / Test-Version

  • Upload
    others

  • View
    6

  • Download
    1

Embed Size (px)

Citation preview

Page 1: Simulink objektorientiert mit C-Kernfunktionen - Anleitung mit Demo- / Test-Version · 2019. 1. 2. · Simulink objektorientiert mit C-Kernfunktionen - Anleitung mit Demo- / Test-Version

Simulink objektorientiert mit C-Kernfunktionen -Anleitung mit Demo- / Test-Version

Dr.-Ing. Hartmut Schorrig

3. Januar 2019

Zusammenfassung

Dieser Artikel stellt Prinzipien dar und ist eine Anleitung für Generierung von Sfuncti-ons in Simulink unter Nutzung von Kern-Funktionalitäten in C. Die Generierung wirdaus Informationen in den C-Headerfiles gesteuert. Es sind wenig zusätzliche Auf-wendungen in Scripts notwendig.

Der Artikel ist gültig zusammen mit dem File Example_ObjO.zip. Dieses File enthältein Beispielmodell, die Sources der Sfunctions, die entsprechenden Generierscriptsund das Inspector-Tool.

Die Zielgruppe für diesen Artikel und die hier vorgestellte Technologie sind Embedded-C-Entwickler, die entweder Simulink noch nicht kennen oder Simulink-Entwickler, diean C orientiert sind und gleichzeitig die Objektorientierte Programmierung im Blickhaben.

1

Page 2: Simulink objektorientiert mit C-Kernfunktionen - Anleitung mit Demo- / Test-Version · 2019. 1. 2. · Simulink objektorientiert mit C-Kernfunktionen - Anleitung mit Demo- / Test-Version

INHALTSVERZEICHNIS 2

Inhaltsverzeichnis

1 Motivation 4

2 Objektorientierte Denkweise und Simulink 5

3 Grafisches Modell, Sfunctions und Codegenerierung 8

4 Praktische Arbeit am Beispiel: Datensammler 10

5 Arbeitsschritte, Tools, Codegenerierung 12

6 Gestaltung der Anwender-Header- und C-Files für die Sfunctions 14

6.1 Datendefinition . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14

6.2 Datendefinition als Simulink-Bus versus private Daten . . . . . . . . . . . . . . . . . . . . 15

6.3 C-Funktions-Prototypdefinitionen für Object-FB und Operation-FB . . . . . . . . . . . . . 15

6.4 Alle @simulink und Argument-Notationsmöglichkeiten im Header . . . . . . . . . . . . . . 18

6.4.1 Schreibweisen von struct-Definitionen . . . . . . . . . . . . . . . . . . . . . . . . . 18

6.4.2 @simulink ctor - Constructor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19

6.4.3 @simulink init - Verbindung von Modulen, Aggregierung, Nachinitialisierung . . . 21

6.4.4 step-Routine, Definition eines Object-FB: @simulink ObjectFB. . . . . . . . . . . . 23

6.4.5 @simulink defPortTypes - Routine für Port-Typedefinitionen aus Parametern . . . 24

6.4.6 @simulink defTlcParam - Bestimmung von CodeGenerier-Parametern . . . . . . . 25

6.4.7 Weitere @simulink ..., Annotation. . . . . . . . . . . . . . . . . . . . . . . . . . . . 27

6.5 Schreibweise der Argumente der relevanten C-Funktionsprototypen . . . . . . . . . . . . 28

6.6 Konzept der Handle, Handle_ptr64_emC.h . . . . . . . . . . . . . . . . . . . . . . . . . . 31

6.7 Ausprogrammierung der C-Funktionen, Reflection . . . . . . . . . . . . . . . . . . . . . . 32

6.8 Allokierung des internen Speichers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34

6.9 Busse als Input und Output / 8-Byte-Alignment . . . . . . . . . . . . . . . . . . . . . . . . 35

6.10 Busse mit boolean-Elemente und Bitfields in struct-Definitionen . . . . . . . . . . . . . . . 37

6.11 Dynamische Festlegung der Porttypen - EntryQueryPortTypesJc . . . . . . . . . . . . . . 38

7 Aspekte der Modell-Gestaltung 40

7.1 Abarbeitungsreihenfolge . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40

7.2 Abarbeitungsreihenfolge bei der Initialisierung (Tinit) . . . . . . . . . . . . . . . . . . . . . 42

7.3 Objektorientierte Simulink-Module, Verbindung über Handle . . . . . . . . . . . . . . . . . 43

7.4 Hinweise für Modellgestaltung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43

8 Basisfunktionen aus der emC-Library 44

Page 3: Simulink objektorientiert mit C-Kernfunktionen - Anleitung mit Demo- / Test-Version · 2019. 1. 2. · Simulink objektorientiert mit C-Kernfunktionen - Anleitung mit Demo- / Test-Version

INHALTSVERZEICHNIS 3

9 Generierung der Sfunctions 46

9.1 Generierscript als Matlab-Script . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47

9.2 Compilierung der C-Quellen mit C++-Compiler . . . . . . . . . . . . . . . . . . . . . . . . 51

10 Internas der Sfunction 52

10.1 Port based oder FB-Abtastzeiten . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52

10.2 Abarbeitung des Modells im Normalmode und Debuggen im C-Code . . . . . . . . . . . . 53

11 Accelerator- und Rapid Accelerator mode 55

11.1 Ablageverzeichnis für Accelerator und Rapid Accelerator . . . . . . . . . . . . . . . . . . . 56

11.2 Welche Sources und Includepfade . rtwmakecfg.m . . . . . . . . . . . . . . . . . . . . . . 57

11.3 Zusätzliche Libraries beim Rapid Accelerator einbinden . . . . . . . . . . . . . . . . . . . 59

11.4 tlc-Files . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60

11.5 Auswahl des Compilers und XML-Steuerdatei für die Compilierung . . . . . . . . . . . . . 61

11.6 Wie kann man Fehler erkennen und beheben? . . . . . . . . . . . . . . . . . . . . . . . . 62

12 Software im Zielsystem mit generierten Simulink-Codes 63

13 Beobachten und Eingreifen mit dem Inspector 64

13.1 FBs für den Inspector im Simulink . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64

13.2 Zugriff mit dem Insspector . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67

13.3 Das Reflection-Prinzip . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67

13.4 Das Inspector-Tool . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68

14 Literatur, Querverweise 68

Page 4: Simulink objektorientiert mit C-Kernfunktionen - Anleitung mit Demo- / Test-Version · 2019. 1. 2. · Simulink objektorientiert mit C-Kernfunktionen - Anleitung mit Demo- / Test-Version

1 MOTIVATION 4

1 Motivation

C ist für Embedded Applikationen der Stan-dard schlechthin. Die Gründe liegen in der Hard-warenähe und der Flexibilität für verschiedeneHardware-Anforderungen. Applikationen werdenaber mehr und mehr komplex, entsprechend dersteigenden Leistungsfähigkeit von Prozessorenund Boards und der gestiegenen Anforderungenan die Software-Applikationen. Die Softwaretech-nologie muss schritthalten, sonst geht der Über-blick über die Software verloren.

Objektorientierte Ansätze, Nutzung C++, Einsatzder UML (Unified Modelling Language) als grafi-sche Unterstützung gibt es seit über 20 Jahren. Dieandere Richtung sind grafisch orientierte Baustein-Verdrahtungen wie sie beispielsweise mit Simatic-CFC oder Simadyn-Struc schon seit Beginn der90-ger Jahre bekannt sind. Simulink mit integrierterCodegenerierung gehört seit langem auch dazu.

Solche Systeme haben aber ihre Eigenheiten.Die gesamte Softwaretechnologie muss umgestelltwerden. Weg von C bedeutet möglicherweise undintuitiv auch das Weg von Hardwarenähe.

Der hier gezeigte Ansatz basiert auf C, das wei-terhin für Kern-Funktionen verwendet wird. Damitist direkt die Hardware in gewohnter Weise an-sprechbar. Der Neuwert mit dem Einsatz von Si-mulink ist der besserer Überblick über die Ge-samtfunktionalität. Das wird durch die grafischeNotationsform erreicht. Simulink arbeitet sehr gutmit C zusammen. Anders jedoch als in Standard-Simulink-Applikationen wird die Objektorientierungin den Vordergrund gerückt. Objektorientierung be-deutet: Stärkere Sicht auf Daten statt auf Funk-tionalität. Da auch die Codegenerierung der Zu-sammenschaltung der Simulink-Blöcke C als Im-plementierungssprache verwendet, steht auf Im-plementierungsebene in gewohnter Weise reinesC zur Verfügung. Es ist also keine Umstellung vonGenerierumgebungen für die Zielplattform notwen-dig.

Eine weitere möglicherweise wichtige Motivationfür diesen Ansatz besteht in Folgendem: Der ausSimulink für ein Zielsystem generierte Code (Em-bedded Coder) ist zwar nach der Generierung ingewohnter Weise mit den bekannten zielsystems-pezifischen Compiler- und Linker-Tools weiter ver-arbeitbar. Der Code kann für sich gelesen und ver-standen werden, jedoch ist die Zuordnung von Co-

deteilen zu grafischen Modellelementen nicht ganzeinfach. Man denke an eine heute verwendete Mo-dellierung mit Simulink für ein Zielprodukt, dass in20 bis 30 Jahren noch gepflegt werden muss. Daskann sich auf eine Parameteranpassung beziehen,den Austausch eines Treibers für neue Hardwa-re, oder die Neucompilierung für eine innovierteHardware-Plattform. Diese Arbeiten sind im rei-nen C möglich. Für die Archivierung der gesam-ten Toolkette ausgehend vom Simulink über er-neute Codegenerierung ist jedoch ein hoher Auf-wand notwendig, der sich beispielsweise auch inder notwendigen Einarbeitung in ein dann schonjahrzehntealtes Tool zeigt. Wenn also heute ab-geschätzt werden kann, dass der Pflegeaufwandfür die Zukunft erheblich sein könnte, dann kanndies ein Grund für die Entscheidung gegen dieSimulink-Technologie sein. Wenn jedoch der er-zeugte Code genügend gut durchschaubar ist fürdie spätere Pflege, dann ist die Entscheidung heu-te für die bessere Softwaretechnologie mit Simu-link deutlich einfacher. Mit dem Einsatz von C imKern sind diese Kernfunktionen im generierten Co-de gut auffindbar und erleichtern wesentlich dieNavigation im generiertem Code für später not-wendige Anpassungen.

Die Objektorientierung in Simulink - unabhängigvon C - stellt eine andere, möglicherweise bessereÜbersicht über die Funktionalität in den Simulink-Modellen dar. Letzlich ist damit eine bessere Or-ganisation der Abarbeitung möglich, was den Re-chenzeitbedarf reduziert. Gemeinsam mit C ist da-mit die schnelle Abarbeitung im Fokus.

Dieser Artikel zeigt die Technologie in der kon-kreten Anwendung am Beispiel eines Modells ein-schließlich Tool zur S-Funktion-Generierung für Si-mulink, eines generierten Codes daraus und denMöglichkeiten der Dateninspektion mit dem ToolInspector. Der Artikel ist gültig mit / für den zip-File www.vishia.org/Smlk/Example_ObjO.zip, deranhand eines Beispiels alle Elemente enthält. Mitdem Inhalt dieses zip.Files sind eigene Arbeitenals Trial-Version möglich. Die Vollversion wird miteinem Vertrag mit vishia mit persönlicher Bera-tung bereitgestellt. Notwendig ist eine Standard-Simulink-Installation (Mathworks), mit EmbeddedCoder (Mathworks) für die Codegenerierung ausden Simulink-Teilen für Embedded Ziel-Hardware.

Page 5: Simulink objektorientiert mit C-Kernfunktionen - Anleitung mit Demo- / Test-Version · 2019. 1. 2. · Simulink objektorientiert mit C-Kernfunktionen - Anleitung mit Demo- / Test-Version

2 OBJEKTORIENTIERTE DENKWEISE UND SIMULINK 5

2 Objektorientierte Denkweise und Simulink

Charakteristisch für Simulink ist die datenflussori-entierte Darstellung: Verbindungspfeile sind immerin Datenflussrichtung gezeichnet. Für den Rege-lungstechniker ist das eine gewohnte Denkweise.In der Objektorientierung, veranschaulicht mit derUML, geht es dagegen um Aggregationen zwi-schen Klassen, Abhängigkeiten, Referenzierungeines Objektes aus einem anderen heraus um des-sen Operationen (Methoden) aufzurufen. Beidesscheinen gegensätzliche Ansätze zu sein. Die Ge-meinsamkeit ist, dass mit grafisch dargestelltenBlöcken die Anwenderprogrammierung besser ge-gliedert dargestellt wird.

Die Objektorientierung ist in der Softwaretechno-logie stark verwurzelt und etabliert. Wechselt mannun zu Simulink, dann ist schon die Frage zu stel-len, ob die Objektorientierung nun passé sei? An-dererseits - Simulink Modelle objektorientiert auf-fassen?

Sobald man sich in Simulink nicht auf der Ebeneder einfachen Verknüpfungen bewegt sondern Blö-cke miteinander verbindet, kann dies ebenso ob-jektorientiert aufgefasst werden. Blöcke stellen Ob-jekte dar. Der entscheidende Schritt hin zur Objek-torientierung ist, dass die Blöcke nicht mit Einzel-signalen verknüpft werden, auch nicht mit Bussen,sondern mit einem Handle, das die Speicheradres-se von Interndaten repräsentiert. Dazu sind min-destens die Blöcke, die Handle bereitstellen und

verarbeiten, als Sfunction zu realisieren die in Cformuliert werden.

Für diesen Ansatz werden im Simulink S-Funktionsbausteine (Sfunctions, Function blocks,FB) unterteilt in

• Object-FB: Enthält die Daten. Enthält ei-ne Operation. Empfängt Datenverbindungenvon anderen Object-FB über Handle. Liefertden eigenen Handle als Output.

• Operation-FB: Enthält keine Daten, gehört zueinem Object-FB, dessen Handle als Inputgegeben ist.

Diese objektorientierte Denkweise in Simulinkkann zu übersichtlicheren Modellen führen. Diessollten die nachfolgenden Beispiele zeigen. Wich-tig ist, dass das für den Regelungstechniker trans-parent nachvollziehbar und verständlich ist, um dienotwendige Akzeptanz zu erzeugen. Für den ob-jektorientiert denkenden Informatiker, der eher ei-ne Unified Modelling Language (UML) gewohnt ist,bietet Simulink damit eine neue nutzbare Plattform.Letztlich kann eine Objektorientierung in Simulinkauch zur Rechenzeiteffizienz des generierten Co-des beitragen, da referenzierte Module von mehre-ren Instanzen genutzt werden können und Kopier-aufwand im Maschinencode eingespart wird.

Das Bild auf der Folgeseite zeigt ein Beispiel, dassin den weiteren Anleitungen benutzt wird:

Im Beispiel geht es um schwingende Messgrö-ßen, die für die weitere Verarbeitung gefiltert, inzwei Komponenten und damit drehende Vektorengewandelt und letzlich statische Werte abgeleitetwerden. Für die Filterung und Vektorbildung wirdein Harmonischer Oszillator eingesetzt, der fremd-bestimmt schwingend einerseits die entsprechen-den Frequenzen filtert und andererseits mit seinenzwei Integratoren zwei möglichst exakt 90 Gradversetzt schwingenden Signale bildet. Damit ste-hen zwei Komponenten im Vektorraum zur Ver-fügung, die als drehender Zeiger die Schwing-bewegung abbilden. Diese Anordnung wird alsOrthogonaloszillator bezeichnet. Mittels Parallel-schaltung der auf Oberschwingungen abgegliche-

nen Orthogonaloszillatoren wird die Grundschwin-gung möglichst sauber abgebildet. Für die Wei-terverarbeitung werden dann die drehenden Vek-toren in stehende Größen wandelt (sogenanntePark-Transformation). Damit kann die Weiterverar-beitung in einer langsameren Abtastzeit erfolgen.Das mag beispielgebend sein und für Applikatio-nen aus elektrischen Netzen (Wechselstrom) undder Mechanik (drehende Wellen) hilfreich.

Ein Orthogonaloszillator als Grundglied kann nunmit einem rein grafischen Modell im Simulink gutbeschrieben werden. In diesem Beispiel wird aberdiese Grundfunktion in C realisiert und als Black-Box für den Regelungsentwickler als Sfunction an-geboten. Damit wird dem Ansatz "Im Kern C " ge-nüge getan. "

Page 6: Simulink objektorientiert mit C-Kernfunktionen - Anleitung mit Demo- / Test-Version · 2019. 1. 2. · Simulink objektorientiert mit C-Kernfunktionen - Anleitung mit Demo- / Test-Version

2 OBJEKTORIENTIERTE DENKWEISE UND SIMULINK 6

Abbildung 1: Simulink Orthogonaloszillator - Objectmodell

Die links im Bild angeordneten Param_OrthOsc2_FB

bilden Object-FBs, die Parameter aufbereiten undüber den Ausgang als Handle zur Verfügung stel-len. Sie werden im Beipiel in einer langsamen Ab-tastzeit berechnet, da die über die Frequenz alssich langsamer veränderten Größe die Paramterangepasst werden müssen. Die Frequenz ist Ein-gangssignal dieser Parameter-FBs.

In Bildmitte sind die eigentlichen Orthogonalos-zillatoren ebenfalls als Object-FB angeordnet. ImUML- oder objektorientierten Sinne aggregierendiese die Parameter-FBs. In Simulink ist im Ver-gleich zu einer UML-Darstellung lediglich die Pfeil-richtung gedreht, vom aggregierten zum nutzen-dem FB. Der nutzende FB erhält die Informationüber das Aggregat als Handle. Diese Handlever-bindung erfolgt initial und fest, im Sinne der Aggre-gation, und braucht also keine Rechenzeit zur Run-time. Eine Assoziation im Sinne der UML - wech-selnde Verbindung zu verschiedenen Instanzen, istauf diese Weise auch möglich und nur eine Ent-scheidung der Steptime-Zuordnung.

Rechts im Bild werden mehrere Operation-FB ge-zeigt, die jeweils eine Operation des OrthOsc2_FB

ausführen. calcpq führt die Wandlung der oszil-lierenden komplexen Größe des Orthogonaloszil-lators (drehender Zeiger) in eine stehende Grö-ße. Dazu ist ein Referenzwinkel notwendig. DerReferenzwinkel wird nicht hier eingespeist, wieman es in klassischer Simulink-Denkweise erwar-

tet. Da der Referenzwinkel eine grundsätzlicheGröße des Objects oder im UML-Sinn der classOrthOsc2_FB ist, ist er selbstverständlich in diesemObject enthalten, bzw. genauer, wird referenziertim aggregierten Angle_abwmf_FB. Darunter bedin-den sich Operation-FB zur Bildung der Amplitu-den der Grundschwingung und der Oberschwin-gungen.

Die Ausgangsgrößen des Moduls sind nun im grüngekennzeichneten Block setOutput zusammenge-fasst. Das ist ein Object-FB, der nur für die Zu-sammenfassung der Ausgangsgrößen in diesemModell genutzt wird. Optisch sieht der FB wie einBus-Creator aus. Funktionell ist es auch so etwaswie ein Bus-Creator, realisiert als Sfunction. Sieheauch Kapitel 4 Seite 10.

Rechts unten ist nun ein weiterer Bus-Creation-ähnlicher FB angeordnet, der die Handle allerObject-FB zusammenfasst und für den Datenzu-griff nach außen für Debugzwecke (Inspector) be-reitstellt, siehe Kapitel 13 Seite 64.

Die meisten der hier sichtbaren Verbindungslei-tungen sind Handle-Verbindungen. Diese werdennur initial verwendet, auch wenn die Abtastzeit-Farbe in diesem Bild dies anders darstellt. DieHandle-Verbindungen entspringen bei Object-FBals Sfunction immer aus dem Output Port 0, rechtsoben. Diese Regelung ist auch bei den hier be-nutzten For-each-Subsystemen beibehalten. Die

Page 7: Simulink objektorientiert mit C-Kernfunktionen - Anleitung mit Demo- / Test-Version · 2019. 1. 2. · Simulink objektorientiert mit C-Kernfunktionen - Anleitung mit Demo- / Test-Version

2 OBJEKTORIENTIERTE DENKWEISE UND SIMULINK 7

Handle-Verbindung führt den konstanten Handlebzw. die Speicheradresse im generiertem Codedes Zielsystems. Sie wird in der init_-Routine inden Interndaten vermerkt, das ist die Aggregati-on. Zur Laufzeit braucht dann diese Verbindungnicht mehr beachtet werden. Das erspart einigesan Datentransfer in der schnellen Abtastzeit. DiePorts sind für Simulink mit der schnellen Abtast-

zeit gekennzeichnet, weil Simulink daraus die Ab-arbeitungsreihenfolge (Execution-order ) ableitet.Insbesondere werden alle Verbindungen zu demInspector-Datensammler, hier rechts unten, nur inder Initialisierung bearbeiten. Der Inspector-Zugriffbelastet auch im Zielsystem nicht die schnelle Ab-tastzeit.

Page 8: Simulink objektorientiert mit C-Kernfunktionen - Anleitung mit Demo- / Test-Version · 2019. 1. 2. · Simulink objektorientiert mit C-Kernfunktionen - Anleitung mit Demo- / Test-Version

3 GRAFISCHES MODELL, SFUNCTIONS UND CODEGENERIERUNG 8

3 Grafisches Modell, Sfunctions und Codegenerierung

Ein Simulink-Modell stellt die Funktionalität über-sichtlich dar, kann komplexere Einheiten als Modu-le oder Komponenten bilden. Letzlich ist solch einModell geeignet um im Kundengespräch die Reali-sierung der Anforderungen darzustellen oder in derSoftwarepflege den notwendigen Überblick zu ver-mitteln. Simulink ist gegebenenfalls dazu bessergeeigneta als C-Codes, deren Struktur mehr oderweniger genau etwa mit UML abgebildet werden.Die Realisierung der Kern-Funktionen in C bildeneine geeignete Brücke zum Implementierungssys-tem für die Zielhardware.

In Simulink wird die gesamte Funktionalität in gra-fischer Notationsform beschrieben. Diese Denk-weise liegt einem Regelungstechniker nahe. Esgibt andererseits das Black-Box-Prinzip: Ein Mo-dul wird benutzt, dessen Verhalten an den Ein- undAusgängen ist wohl definiert. Wie das Modul die-se Funktion erfüllt, ist bei der Nutzung des Modulsnicht wichtig. Sehrwohl kann das Modul im innerenauch betrachtet werden, in einer anderen Betrach-tungsebene. Das Black-Box-Prinzip ist dem Rege-lungstechniker zumeist geläufig.

Das Beispielmodell zeigt deutlich, dass die Funk-tionalität gut dargestellt wird mit Nutzung der Mo-dule der OrthOsc2_FBs. Das wesentliche am Mo-dell ist die Zusammenschaltung. Der Innenaufbauder Module würde in Simulink einige Additionen,Multiplikationen und Speicherglieder zeigen, nichtsehr spektakulär. Diese Dinge lassen sich einfachauch in C programmieren. Die hier beschriebe-ne Denkweise geht davon aus, dass im Kern -aus verschiedenen Gründen - C genutzt werdensoll. In C sind auch Zuordnungen zu Abtastzeiten,Steuerungen wann Parameter neu berechnet wer-den (wer ruft dies auf) und dergleichen günstig zuprogrammieren, ebenso Synchronisationsmecha-nismen mit dem Betriebssystem.

Sfunction-Wrapper

Die Sfunctions sind FunctionBlocks in Simulink,die eine direkte in C geschriebene Funktionali-tät enthalten. Um die C-Funktionalität im Simu-link abarbeiten zu können, sind einige Aufwen-dungen notwendig. Beispielsweise muss Simu-link abfragen können, wieviel In- und Output-Ports es gibt, welche Abtastzeiten zugeordnetsind usw. usf. Der Aufruf der Funktionalität inder Abtastzeit ist dabei fast der kleinere Auf-wand. Jedoch müssen auch dafür die Input-Daten

aus dem Simulink-Datenhaushalt gelesen, aufbe-reitet, und die Output-Daten wieder geschriebenwerden. Dieser Zusatzaufwand mag als Wrapperfür kleine C-Funktionalitäten hoch erscheinen, istaber rechenzeittechnisch gesehen nicht das Pro-blem. PC-Prozessoren sind schnell. Jedoch ist esein programmtechnischer Aufwand. Ein Sfunction-Wrapper um die eigentlichen C-Kernanweisungenherum ist ein C-File, das als main-File für einespezielle MEX -Dynamic Library für Simulink com-piliert wird. Der benutzte Compiler ist dabei meistein Visual-Studio-Standard-Compiler, der von Mat-lab über das mex-Command aufgerufen wird. DieseDinge sind in der Matlab-Hilfe bekannt und erläu-tert.

tlc-Files

Simulink kennt weiterhin den Accelerator-Mode.Dabei wird der Code nicht mit den eben vorgestell-ten Sfunction-Wrapper aufgerufen, sondern derCode wird compiliert und als Maschinencode ab-gearbeitet. Ein tlc-File (Target Language Compiler-Controllfile) für jede Sfunction beschreibt, wie diedirekt in C geschriebenen Teile richtig einzubindensind. Ein tlc-File enthält Steueranweisungen undQuellcodes mit Replacement-Elementen.

Die tlc-Files dienen letztlich auch dazu, für die Co-degenerierung im Zielsystem die direkt beigestell-ten C-Codes richtig einzubinden.

Standard-Angebot in Matlab für Sfunctions

Matlab-Simulink bietet zur Anwenderunterstützungdieses Systems der Sfunction - eigene C-Codeseinbinden - Unterstützung an. Das Legacy codetool, im Simulink-Standardumfang enthalten, kannverwendet werden, um aus einer Beschreibungder Einbindung der C-Codes in Simulink in ei-nem Matlab-Script-File die entsprechenden Wrap-per und tlc-Files zu generieren. Das Legacy co-de tool ist erstrangig dafür gedacht, eher komple-xen C-Codes in ein Simulink-Modell aufzurufen.Für die Einbindung eher kleiner C-Module ist derSchreibaufwand etwas hoch, da für jede einzel-ne C-Funktion ein extra Matlab-Script geschriebenwerden muss. Sonderfälle, etwa String-Parameteroder parameterabhängige Typen von Ein- und Aus-gängen werden nicht unterstützt.

Schreibt man dagegen die Sfunction-Wrapper undtlc-Files manuell, dann sind die Möglichkeiten derGestaltung sehr hoch. Beispielsweise kann der

Page 9: Simulink objektorientiert mit C-Kernfunktionen - Anleitung mit Demo- / Test-Version · 2019. 1. 2. · Simulink objektorientiert mit C-Kernfunktionen - Anleitung mit Demo- / Test-Version

3 GRAFISCHES MODELL, SFUNCTIONS UND CODEGENERIERUNG 9

Typ von Ein- und Ausgängen (Anzahl Vektorele-mente, float oder int, Bus-Typ) und die Zeitschei-benzuordnung mit der Einbettung im Modell gere-gelt werden. Die angeschlossenen Verbindungenim Modell bestimmen diese Eigenschaften. Die Ei-genschaften werden in den Wrapper-Funktionender Sfunction aus der Simulink-Umgebung abge-fragt und abgelegt. Bei der Codegenerierung kön-nen diese Daten dann einerseits den C-Funktionenaufbereitet übergeben werden, andererseits gibt

es auch in den tlc-Files %if-Anweisungen, diezum Zeitpunkt der Codegenerierung entscheiden,welche Programmzeilen generiert werden. - DieSfunction-Wrapper und tlc-Files können anhandvon Mustern und der Hilfe-Doku erstellt werden.Jedoch ist das Selbstschreiben durchaus aufwän-dig und damit auch fehleranfällig.

Die dritte Möglichkeit ist eine grafische Bedienungzur Bestimmung der Eigenschaften von Sfuncti-ons.

Generator für die Sfunction-Wrapper und tlc-Files direkt aus den Informationen in den Headerfi-les

Wenn kleine und viele Kern-Funktionen in C in einSimulink-Modell eingebettet werden sollen, dannist die Arbeit der Erstellung der Sfunctions für je-de Kern-C-Funktion mit dem Legacy-code-tool zuhoch. Es muss ausreichend sein, mit wenigen An-notations in den Headerfiles der C-Programmeeinen Generator so zu steuern, der die Sfunction-Wrapper und tlc-Files automatisch ohne Zusatz-arbeit erstellt. Die Komplexität wird hier von derEinzelbearbeitung in das Generiertool verlagert.Hat man spezifische Anforderungen, dann wirddies im Generiertool angepasst und steht dann füralle Sfunctions zur Verfügung. Der einzelne C /Simulink-Entwickler muss damit nicht alle Detailstäglich bearbeiten, die Arbeit der spezifischen An-passung lässt sich zentralisieren. Dabei ist Auf-wand und Verständnis für diese Anpassungen

durchaus vom einzelnen Entwickler im Mittelstanderbringbar.

Im folgenden Kapitel werden die Schreibweisenin den eigenen C-Codes in den Headerfiles ge-zeigt, wie sie für die Standardgenerierung verwen-det werden. Die Schreibweisen sind anpassbar andie jeweils gültigen Style-Guides.

Die Generierung wird mit einem ZBNF-Parserund JZtxtcmd-Generator ausgeführt. Diese beidenTools sind als Open-Source verfügbar. Beide wer-den mit textuellen Scripts gesteuert. Diese Scriptsenthalten das Knowhow der Sfunction-Wrapper-und tlc-Generierung. Mit Anpassung und Weiter-entwicklung der Scripts sind weitergehende Anfor-derungen erfüllbar.

Siehe folgenden Abschnitt und Abschnitt 9.

Page 10: Simulink objektorientiert mit C-Kernfunktionen - Anleitung mit Demo- / Test-Version · 2019. 1. 2. · Simulink objektorientiert mit C-Kernfunktionen - Anleitung mit Demo- / Test-Version

4 PRAKTISCHE ARBEIT AM BEISPIEL: DATENSAMMLER 10

4 Praktische Arbeit am Beispiel: Datensammler

C-Code des Datensammlers im Beispielmodell setOutput

Dieses Kapitel soll am einfachen Beispiel zeigen, wie der Datensammler setOutput im Beispielmodellin C in einem Headerfile programmiert wird und wie sich diese Arbeitsweise in die Modellierung einfügt.Die detaillierte Erläuterung der Gestaltungsmöglichkeiten in einem Headerfile finden sich im Kapitel 6,Seite 14

Die Daten werden vom gezeigten Modell erarbei-tet und sollen hier einem beliebig anderem Mo-dul bereitgestellt werden. Im Beispiel muss die Da-tenaufbereitung in einer schnellen Abtastzeit ar-beiten, beispielsweise 25 us für 240 Abtastwer-te einer drehenden Welle mit 10000 U/min. Diebereitgestellten Daten sind aber statische Datender Drehbewegung und beispielsweise in einemTakt von 10 ms weiter zu verarbeiten. Angenom-men, dies passiert in 2 verschiedenen Prozesso-ren. Die 25 us-Abtastzeit läuft in einem Prozes-sor ohne Betriebssystem im Interrupt. Die Datenwerden im Zielsystem in ein Dual-Port-RAM ge-schrieben, beispielsweise mit einem FPGA reali-siert. Der zweite Prozessor hat ein Linuxkernel,Kommunikations-Schnittstellen und/oder ein User-Interface und kann den 10 ms-Interrupt passendverarbeiten. Das Datenschreiben in 25 us und dasDatenlesen in 10 ms arbeiten damit aber nichtzeitlich koordiniert, asynchron. Es kann sein, dasswährend des Lesens neu geschrieben wird.

Die Daten sollten konsistent sein. Die Frage derOrganisation der Abarbeitung hat wenig mit dereigentlichen Funktion zu tun und wäre viel zukomplex in das Simulink-Modell hineinzutragen.Daher sind diese Dinge in C besser aufgeho-ben, möglicherweise auch in personeller oderVerantwortungs-Trennung für deren Programmie-rung.

Dennoch muss die Entscheidung, welche Da-ten in das Dateninterface stehen sollen, ausder Simulink-Ebene einfach zugänglich sein: InSimulink wird bestimmt, um welche Daten esgeht. In der Hardware- Betriebssystem- undAblauforganisations-Ebene wird bestimmt wie dieDaten transportiert werden und wie auf sie zuge-griffen wird.

Zum Modell zugehörig gibt es einen Headerfile, imUnterverzeichnis +genSfn. Dieses ist im Simulink-Editor bearbeitbar und wird dort auch für den C-Code highlighted dargestellt (hier gekürzt):

typedef struct Data_Output_Test_OrthOsc2_t

{

/**A sequence number to check the consistence of data. */

int32 seq;

/**The static values of fundamental osciallation. */

float_complex pq1[2];

/**Magnitude of the fundamental oscillation*/

float m1[2];

.....

} Data_Output_Test_OrthOsc2;

/**ObjectFB which contains the outputs.

* @param idenntObj for debugging

* @simulink Sfunc

*/

INLINE_Fwc void ctor_Output_Test_OrthOsc2(Output_Test_OrthOsc2* thiz, int identObj)

{ ....

/**Sets the values of the ObjectFB which contains the outputs.

Page 11: Simulink objektorientiert mit C-Kernfunktionen - Anleitung mit Demo- / Test-Version · 2019. 1. 2. · Simulink objektorientiert mit C-Kernfunktionen - Anleitung mit Demo- / Test-Version

4 PRAKTISCHE ARBEIT AM BEISPIEL: DATENSAMMLER 11

* @simulink Sfunc

*/

INLINE_Fwc void set_Output_Test_OrthOsc2

( Output_Test_OrthOsc2* thiz, float_complex pq1[2]

, float m1[2], float m2[2], float m3[2])

{ .....

Will man nun aus der Simulink-Intension herausandere oder weitere Daten einbringen, dann ist dieEditierung dieses Files auch einem Regelungsent-wickler zumutbar, ähnlich wie auch Matlab-Scriptstextuell sind. Die Schreibweise ist übersichtlich.

Die hier mit ..... angedeuteten Implementierun-gen der Operationen stehen ebenfalls direkt imHeader und haben keine hohe Komplexität. Selbstdie Organisation des Wechselpuffers ist versteh-bar. Die set-Operation lautet hier im Volltext:

/**Sets the values of the ObjectFB which contains the outputs.

* @simulink Sfunc

*/

INLINE_Fwc void set_Output_Test_OrthOsc2(Output_Test_OrthOsc2* thiz

, float_complex pq1[2],float m1[2], float m2[2], float m3[2])

{

int32 seq = thiz->ix +1;

Data_Output_Test_OrthOsc2* data = &thiz->data[seq & 1];

data->seq = seq;

memcpy(data->pq1, pq1, sizeof(data->pq1));

memcpy(data->m1, m1, sizeof(data->m1));

memcpy(data->m2, m2, sizeof(data->m2));

memcpy(data->m3, m3, sizeof(data->m3));

thiz->ix = seq; //write back for usage after fill data.

}

Der C-Programmierer erkennt schnell die Funkti-on. Wenn weitere Daten eingebracht sind, dannwird eine weitere gleichartige Zeile ’nach Schema’ergänzt. Kleine Flüchtigkeits-Schreibfehler werdenbeim Compilieren gemeldet.

Nach Editierung wird das Script+genSfn/TestOrthOscObjO_genSfn.m ebenfallsaus dem Matlab heraus gestartet. Damit wird dieSfunction neu erzeugt und kann sofort verwendetwerden. Die Anpassung im Modell ist in Simulinkbeschrieben und bekannt (Eingänge verdrahten).

Page 12: Simulink objektorientiert mit C-Kernfunktionen - Anleitung mit Demo- / Test-Version · 2019. 1. 2. · Simulink objektorientiert mit C-Kernfunktionen - Anleitung mit Demo- / Test-Version

5 ARBEITSSCHRITTE, TOOLS, CODEGENERIERUNG 12

5 Arbeitsschritte, Tools, Codegenerierung

Der hier beschriebene Ansatz geht von folgendemaus:

• Kern-Funktionen und Datenstrukturen wer-den in C formuliert.

• Aus den Headerfiles wird der Code der Wrap-per für Simulink-Sfunctions generiert. Dieserufen dann direkt die C-Kernfunktionen auf.

• Aus den Datentypdefinitionen in den Header-files werden Matlab-Busdefinitionen in *.m-Files generiert, die dann im Workspace desMatlab zur Verfügung stehen.

• Aus den Headerfiles werden die sogenann-ten tlc-Files generiert, die Simulink sowohlfür die Codegenerierung für ein Zielsystembraucht als auch für den Accelarator-Modeim Simulink.

• Mit den Sfunctions und weiteren Simulink-Elementen wird ein Modell erzeugt,dass die Zusammenschaltung der Kern-Funktionalitäten in C (in den Sfunctions) be-schreibt. Dabei wird nach Object-FB undOperation-FB unterschieden und eine Ob-jektOrientierte Denkweise unterstützt. DerAufruf der Operation-FB zu einem zugehö-rigen Object-FB kann dabei in einem an-deren Modell-Bestandteil erfolgen (adäquatzum Aufruf einer public-Methode einer Klas-se aus einer anderen Klasse).

• Ein Simulink-Modul kann nun wiederum soaufgebaut werden, dass es als AtomarenSubsystems oder referenziertes Modell auchals Object-FB erscheint mit einem Hand-le nach außen und Handles von außen fürOperation-FBs (Operation-Module). Das Ob-jektOrientierte Prinzip kann also auch auf hö-herer Ebene im Simulink verwendet werden.

• Aus einem so gebildeten Gesamt-Simulink-Subsystem wird Code für ein Zielsystem ge-neriert.

• Die Einbindung des Codes in die Laufzeitum-gebung des Zielsystems wird wie gewohnt inC realisiert. Die aus Simulink generierten Co-des werden in die bestehende Generierum-gebung eingebunden.

• Es wird empfohlen den Zielsystem-Codeauch als Executable für den PC zu com-pilieren und auch auf dem PC testen zukönnen. Eine notwendige Umgebung kannmit Simulink-Mitteln erstellt werden und wirdmit der PC-exe insbesondere über Socket-Kommunikation gekoppelt. Dazu gibt es fer-tige FBs von vishia.

• Im Simulink-Modell kann ein sogenann-ter Inspector-Service-FB angeordnet, überden von außen über Socketkommunikati-on auf Interndaten des laufenden Simulink-Modells zugegriffen wird. Es sind dies dieInterndaten, die als C-Kerne definiert wur-den. Das Tool für den Zugriff ist der In-spector mit eine offen gelegten Socket-Kommunikationsprotokoll.

• Der Inspector kann auch im Zielsystem ein-gesetzt werden.

Damit sind folgende Tools für die Arbeit notwendig:

• C/C++-Entwicklungsumgebung für PC undfür das Zielsystem

• Matlab mit Simulink von Mathworks, enthältdie Unterstützung für Sfunctions.

• Codegenerierung aus Simulink als Zusatz-Modul für Simulink von Mathworks.

• Codegenerierung für Wrapper der Sfunc-tiones, Busse und tlc-Files von vishia.Dies ist Nicht-Open-Source. Lizenz erforder-lich.

• Einige C-Systemfunktionen von vishia,Open-Source.

• Der ZBNF-Parser und JZtxtcmd-Textgeneratorvon vishia, Open-Source, Java

• Der Inspector von vishia, Open-Source, Java

Der vierte Punkt erfordert eine perönliche Kon-sultation mit vishia. Wenn eine Erstbetreuung von4 Arbeitstagen und mindestens ein 1-jähriger Be-treuungsvertrag im Wert von insgesamt 8 Ar-beitstagen für ein Entwicklungsteam. Dieses Ent-wicklungsteam erhält damit die Lizenz für zeit-lich unbegrenzte Nutzung. Die Betreuung kann

Page 13: Simulink objektorientiert mit C-Kernfunktionen - Anleitung mit Demo- / Test-Version · 2019. 1. 2. · Simulink objektorientiert mit C-Kernfunktionen - Anleitung mit Demo- / Test-Version

5 ARBEITSSCHRITTE, TOOLS, CODEGENERIERUNG 13

sich insgesamt auf die Unterstützung der Simulink-Handhabung für Codegenerierung im Zielsystemoder auch auf Belange der C-Programmierungoder Modellierung beziehen. Die Scripts der Gene-rierung sind textuell und damit auch eigenständiganpassbar beispielsweise an Simulink-Versionen.Es kann aber im Rahmen des Lizenzvertragesauch eine längerfristige Betreuung vereinbart wer-

den. Die Lizenz ist an ein Entwicklungsteam vonca. 5..10 Personen gebunden. Wird dieses Toolin größeren Firmen abteilungsübergreifend genutztoder soll es Partnerfirmen weitergegeben werden,so ist dazu jeweils eine eigene Lizenz erforder-lich. Bei entsprechendem Umfang kann dies kos-tengünstiger erfolgen.

Page 14: Simulink objektorientiert mit C-Kernfunktionen - Anleitung mit Demo- / Test-Version · 2019. 1. 2. · Simulink objektorientiert mit C-Kernfunktionen - Anleitung mit Demo- / Test-Version

6 GESTALTUNG DER ANWENDER-HEADER- UND C-FILES FÜR DIE SFUNCTIONS 14

6 Gestaltung der Anwender-Header- und C-Files für die Sfunctions

Die Headerfiles in C enthalten alle Informationen die für das jeweilige Modul notwendig sind für dieS-Funktionsgenerierung. Außer dem allgemeinen Generierscript laut Kapitel 9.1, Seite 47 sind keineweiteren Scripts notwendig.

6.1 Datendefinition

Das Beispiel soll wiederum als Muster gelten. Der Typ des Object-FB OrthOsc2_FB, sagen wir konse-quent die class OrthOsc2_FB wird in C in einem Headerfile als struct definiert:

/**Internal data of a OrthogonalOscillator.

* @simulink no-bus

*/

typedef struct OrthOsc2_FB_t

{

ObjectJc obj; //:The base structure

Param_OrthOsc2_FB* par; //:Reference to parameter, maybe calculated in other time.

Angle_abwmf_FB* anglep; //:Reference to angle, null is admissable.

/**Couple factors. Note: kB should be negative for same difference B-X, A-X*/

float kA, kB;

float_complex yab; //:Orthogonal components of oscillation.

float_complex ypq; //:optional: Orthogonal components as fundamental values, ...

float m, mr; //:optional: Magnitude and its reciproke, if calculated

//

float b_; //:internal b component

} OrthOsc2_FB;

Die struct-Definition fasst Daten zusammen undist der erste Schritt hin zu einer Objektorientierung.Dies sind die Daten des Object-FB im Simulink.

Wenn bestehende Quellen in dieses Schema ge-packt werden sollen um Simulink zu nutzen, bisheraber eher auf statische Einzelvariable in C-Filesorientiert wurde, dann stellt die Zusammenfassungzueinandergehöriger Variable in einer struct dererste wichtige Schritt dar, der im konventionellemC begangen wird. Einzelvariable sind in Speicher-platz und Adressierung im Maschinencode iden-tisch mit der Zusammenfassung der Variablen in ei-ner struct und deren statischer Instanziierung. Esmuss lediglich formell etwas umgeschrieben wer-den. Dies ist aber der entscheidende Schritt bei-spielsweise auch zu einer mehrfachen Instanziie-rung eines Moduls, sei es auch nur für Testzwecke.

Die typedef struct selbst und die Einzelele-mente können und sollten im Header kommen-tiert werden. Hier wird entweder die sogenann-

te Javadoc-Notationsform verwendet, angelehnt andie sehr einheitliche Schreibweise der Kommentie-rung in Java, oder es erfolgt eine platzsparendeZeilenend-Kommentierung. Für die Codegenerie-rung für Simulink werden die Kommentare dannautomatische auch in den Simulink-Einheiten er-scheinen.

Die struct für einen Object-FB muss dann mitdem Element

ObjectJc obj;

beginnen wenn der Object-FB mit anderen FBsverbunden wird. Das ist notwendig weil im Si-mulink die Verbindung der FBs geprüft werdenmuss. Ein weiterer Grund ist die Unterstützungdes Zugriffs auf die internen Daten mittels desReflection-Mechanismus, siehe Kapitel 13.3 Sei-te 67. Das Datenelement ObjectJc benötigt insge-samt 24 Byte und muss nur bei den Hauptstruk-turen der Object-FB vorhanden sein. Für das Ziel-

Page 15: Simulink objektorientiert mit C-Kernfunktionen - Anleitung mit Demo- / Test-Version · 2019. 1. 2. · Simulink objektorientiert mit C-Kernfunktionen - Anleitung mit Demo- / Test-Version

6 GESTALTUNG DER ANWENDER-HEADER- UND C-FILES FÜR DIE SFUNCTIONS 15

system kann die struct ObjectFB reduziert wer-den auf eine einfache Variable, die auch dort dieDebugmöglichkeiten unterstützt.

Object-FB, die keine Operation-FB haben undauch nirgends weiter referenziert werden, benöti-gen die struct ObjectFB grundsätzlich nicht. Da-mit braucht bei umfangreiche aber nicht verküpf-

te Sfunctions mit Anwenderquellen das ObjectJc-Konzept (emC-Library) nicht unbedingt berücksich-tigt werden, was den Umstieg von bestehendenAnwendungen erleichtert. Diese Object-FB dür-fen dann aber keine Aggregationen zu anderenObject-FB haben. Damit haben sie typischerweiseauch keine @simulinik init-Operation.

6.2 Datendefinition als Simulink-Bus versus private Daten

Wenn eine solche typedef struct mit dem Kenn-zeichen (tag) im Comment:

* @simulink bus

versehen ist, dann wird bei der Codegenerierungfür Simulink eine Simulink-Busdefinition in ein *.m

matlab-Script generiert, dessen Abarbeitung danndie struct-Daten als Matlab-Busdefinition abbil-det. Man kann die Daten dann als Bus in Simulinkausgegeben und mit den Simulink-Modellmittelndessen Datenelemente abgreifen. Zu beachten istjedoch, dass der Bus bei der Codegenerierung aufeinem eigenen Datenbereich platziert wird, alsoDaten kopieren. Für die Rechenzeiteffektivität istdas nicht die günstigste Lösung. Wenn aber imnichtrechezeitkritischem Bereich mit Daten im Si-mulinkmodell gut gearbeitet werden kann, dann istdies zu empfehlen.

struct die als Busse abgebildet werden sollten in

der Regel keine Zeiger enthalten. Die Anordnungder Daten muss so gewählt werden, dass bestimm-te Alignment-Dinge beachtet sind. Dies gilt auchfür einige Zielplattformen. Siehe dazu http://www.

vishia.org/SwEng/html/int_short.html. Die in-ternen Simulink-Busdaten werden direkt auf diestruct abgebildet. Die Richtigkeit dieses Mappingwird in der startup-Phase überprüft.

Die internen Daten der Function-FB brauchen inder Regel nicht als Bus im Simulink präsentiertwerden. Grundsätzlich kann man hier objektori-entiert denken und die Daten als private anse-hen. Um die Daten zu beobachten, im Simulinkin der Run-Phase, können die Inspector-FBs ver-wendet werden, siehe 13.1, Seite 64. Der FBGetValue_Inspc liest Daten aus intern-struct, gibtsie am Ausgang aus, anschließbar beispielsweisean einen Scope im Simulink, und ist textuell konfi-gurierbar.

6.3 C-Funktions-Prototypdefinitionen für Object-FB und Operation-FB

Im Headerfile nach der Datendefinition folgen ent-weder Funktionsprototypdefinitionen oder Inline -Funktionsdefinitionen. Nach dem Schema der Ob-jektorientierten Programmierung in C tragen dieFunktionen als Suffix den Namen der zugehöri-

gen Datenstruktur und übernehmen als erster Ar-gument thiz den Zeiger auf die Daten. Funktio-nen, aus denen Simulink-FBs gebaut werden sol-len, sind im Kommentar mit @simulink ... be-zeichnet.

/**Initializes thiz object with given parameter.

* @param identObj Identifier, will be stored in the ObjectJc base data, for debugging.

* @param Tstep The step- or sampling time for this module.

* @simulink ctor

*/

OrthOsc2_FB* ctor_OrthOsc2_FB(ObjectJc* othiz, int32 identObj, float Tstep);

Dies ist der Constructor eines Object-FB. DieKennzeichnung als Constructor erfolgt mit

@simulink ctor

Im Gegensatz zu allen anderen objektorientier-ten C-Funktionen übernimmt der Constructor wenn

Page 16: Simulink objektorientiert mit C-Kernfunktionen - Anleitung mit Demo- / Test-Version · 2019. 1. 2. · Simulink objektorientiert mit C-Kernfunktionen - Anleitung mit Demo- / Test-Version

6 GESTALTUNG DER ANWENDER-HEADER- UND C-FILES FÜR DIE SFUNCTIONS 16

so angegeben nicht den Typzeiger sondern einenObjectJc*-Zeiger. Die Instanz muss mit 0 initiali-siert sein, die Kopfdaten des ObjectJc, insbeson-dere die eigene Adresse und die Byteanzahl desgesamten Object müssen gesetzt sein. In den ge-nerierten Codes ist dies so vorgesehen.

Alle Arguemnte des Constructors sind in Simulink

non-tunable Parameter der Sfunction. Sie werdenin Simulink entweder numerisch als double oderals String angegeben und entsprechend konver-tiert. Der Rückgabetyp des Constructor ist der In-stanzzeiger selbst, mit gleichem Wert wie othiz.Diese Schreibweise hat eher semantischen Cha-rakter für die direkte C-Programmierung.

/**Prepares the instance data.

* @param par aggregation to the parameter.

* @param angle aggregation to instance which contains the angle of the signal.

* @simulink init

*/

void init_OrthOsc2_FB(OrthOsc2_FB* thiz, Param_OrthOsc2_FB* par, Angle_abwmf_FB* angle);

Die mit @simulink init gekennzeichnete C-Funktion ist die Initialisierung des Object-FB, dieVersorgung mit Aggregationen zu anderen FBs.Die Aggregierung sollte nach der Theorie zwarbereits im Constructor erfolgen. Praktisch funktio-niert dies aber auch in der UML oder in Java-Anwendungen nicht, wenn Aggregationen gegen-seitig stattfinden sollen. Daher ist auch in ande-ren Anwendungen eine sogenannte Nachinitialisie-rung gebräuchlich. Alle Zeiger-Argumente dieser

C-Funktion werden in Simulink auf Eingänge derTinit-Zeitkonstante definiert. Alle Nicht-Zeiger-Argumente sind non-tunable Parameter. In Simu-link bestimmt die Verdrahtung der Tinit-Eingängeder FBs die Aggregationen. Ein FB gibt seinen ei-genen Datezeiger (thiz) an andere FBs weiter,die diesen als Aggregation speichern. Damit kannin schnellen Zeitkonstanten die Daten der aggre-gierten FBs direkt gelesen bzw. deren Operationenaufgerufen werden.

/**Step routine. It calulates the stored values of Orthogonal Oscillation.

* @param xAdiff Difference between Input and yaz_y Signal

* @param xBdiff same as xAdiff for only single input, or orthogonal difference

* @param yaz_y variable to store the a-Output.

* @param ab_Y variable to store the complex orthogonal output..

* @simulink Object-FB, accel-tlc

*/

INLINE_Fwc void step_OrthOsc2_FB(OrthOsc2_FB* thiz, float xAdiff, float xBdiff

, float* yaz_y, float_complex* ab_y)

{

//C-Code

}

Dies ist die inline-Formulierung der step-C-Funktion. Das Makro INLINE_Fwc wird entwedermit inline für C++-Compilierung ersetzt, odermit static für C-Compilierung. Mit dieser inline-Formulierung wird im Zielsystem die Laufzeit op-timiert.

Mit der Kennzeichnung @simulink ObjectFB

ist dies die Operation eines Object-FB, damitwird also eine Sfunction gebildet. Die in derReihenfolge im Headerfile davor aufgefunde-nen @simulink ctor und @simulink init C-

Funktionen gehören zu dieser S-Funktion alsOperation-FB bzw. auch zu weiter folgendenOperation-FB. Will man mit den gleichen Da-ten verschiedene Operation-FB mit verschie-denen Constructoren haben, dann kann manauch mehrere @simulink ctor usw. angeben,es gilt die Reihenfolge im Headerfile. Im filesrcc_FB/OrthOsc_FB.h zugehörig zum Beispielm-odell findet sich neben diesem Object-FB derstepNoAngle_OrthOsc2_FB mit selben Constructoraber anderer initFunktion.

Page 17: Simulink objektorientiert mit C-Kernfunktionen - Anleitung mit Demo- / Test-Version · 2019. 1. 2. · Simulink objektorientiert mit C-Kernfunktionen - Anleitung mit Demo- / Test-Version

6 GESTALTUNG DER ANWENDER-HEADER- UND C-FILES FÜR DIE SFUNCTIONS 17

Mit der Kennzeichnung @simulink ... , accel-tlc

wird erreicht, dass beim Accelerator-Mode des Si-mulink der Inhalt des tlc-Files verwendet wird, umoptimalen Ablaufcode zu generieren. Das ist meistzweckmäßig, aber in wenigen Fällen nicht möglich.Siehe dazu Erläuterungen von Mathworks zumFlag SS_OPTION_USE_TLC_WITH_ACCELERATOR.

Die Argumente sind entweder Eingänge (nume-risch), Ausgänge oder tunable-Parameter, sieheFolgekapitel.

Ein Object-FB ohne Sonderkennzeichnung allo-kiert den notwendigen Speicherplatz innen, spei-

chert in einem sogenannten DWork vector denZeiger auf den Speicherplatz und einen zugehö-rigen Handle als Index auf eine Zeigertabelle alsuint32-Wert. Der Handle wird am Ausgang 1 rechtsoben für die Tinit-Zeitkonstante ausgegeben, unddarunter für die step-Zeitkonstante der Operati-on. Für ein 32-bit-Zielsystem führen diese Aus-gänge direkt die Speicheradresse als uint32 typi-siert abgelegt. Der Tinit-Ausgang des thiz-Handlesoll für die Aggregations-Verdrahtung benutzt wer-den, der Tstep-Ausgang für Opertion-FBs zu die-sem Object-FB.

/**Outputs the ab vector of this.

* @simulink Operation-FB, accel-tlc

*/

INLINE_Fwc void ab_OrthOsc2_FB(OrthOsc2_FB* thiz, float run, float_complex* ab_y)

{

ab_y->re = thiz->yab.re;

ab_y->im = thiz->yab.im;

}

Dies ist ein einfacher Operation-FB. Das thiz-Argument erscheint hier als erster Input, der ge-samte FB hat eine Abtastzeit. Diese wird folg-lich vom Anschluss des Handle des zugehörigen

Operation-FB bestimmt, oder von passend einge-setzten Rate transition blocks des Simulink undvon den anderen Signalen.

Page 18: Simulink objektorientiert mit C-Kernfunktionen - Anleitung mit Demo- / Test-Version · 2019. 1. 2. · Simulink objektorientiert mit C-Kernfunktionen - Anleitung mit Demo- / Test-Version

6 GESTALTUNG DER ANWENDER-HEADER- UND C-FILES FÜR DIE SFUNCTIONS 18

6.4 Alle @simulink und Argument-Notationsmöglichkeiten im Header

Syntaktisch sind die Notationsmöglichkeiten beim Parsen des Headerfiles bei der Simulink-Generierungfestgelegt. Der Parser mit dem Syntaxfile zbnfjax/zbnf/Cheader.zbnf verarbeitet auch die Comment-Anteile. Es wird damit vermieden, dass es wegen eines Schreibfehlers Irritationen gibt (C-Funktionerscheint nicht als Operation-FB usw.).

6.4.1 Schreibweisen von struct-Definitionen

/**Comment for docu

* @simulink no-bus.

* //@ simulink bus.

*/

typedef struct MyType_t {

union { Object object; } base;

MyOtherType* aggregation;

HandlePtr_emC(struct HandleType_t, handle);

/**Comment for docu. */

int16 ivar1, ivar2;

int32 ivar3;

float var1, var2;

int32 bit1:1, bit2:1, bitfield: 4;

} MyType_s;

• Anntotation @simulink bus. erzeugt einen Beitrag im genBus.m-File zur Generierung eines Bus-ses mit Namen der struct. no-bus hat keine Auswirkung, ist aber deutliche Kommentierung.

• Die struct soll mit union { Object object; } base; beginnen wenn es sich um eine struct ei-nes Object-FB handelt. Damit sind über Reflection sowohl Typ-Informationen vorhanden, als auchder symbolische Datenzugriff wird damit realisiert. Bei struct-Definitionen für Sub-Daten oder fürBusse ist dies nicht notwendig. Hinweis: Die struct ObjectJc belegt 24 Byte. Für ein Zielsystem,das keine Reflection nutzt oder einen Reflectionzugriff über den sogenannten InspectorTarget-Proxy unterstützt, ist diese struct ObjectJc auf 1 Speicherwort reduziert und enthält nur denIndex der zugehörigen Typekennzeichnung. Es wird also kaum Speicherplatz benötigt.

• Bei der Aufteilung der Daten in der struct sollte immer darauf geachtet werden, dass ein Ali-gnment eingehalten wird, siehe dazu 6.9. Das ist eine kleine Überlegung bei der Anlage derStrukturen mit einer großen Wirkung bei Detailproblemen des Speicherzugriffs.

• Zeigertypen dürfen in struct dann stehen, wenn diese struct nicht als Bus abgebildet ist, alsonicht im Simulink erscheint.

• Für Referenzen in Bussen wird die Definition HandlePtr_emC(TYPE, NAME) verwendet. Siehe 6.6,Seite 31. Der Reflection-Zugriff kennt und benutzt diesen Mechanismus, so dass die tatsächlichreferenzierte Instanz dennoch sichtbar ist.

• Bitfields in Bussen: Siehe 6.10, Seite 37.

Page 19: Simulink objektorientiert mit C-Kernfunktionen - Anleitung mit Demo- / Test-Version · 2019. 1. 2. · Simulink objektorientiert mit C-Kernfunktionen - Anleitung mit Demo- / Test-Version

6 GESTALTUNG DER ANWENDER-HEADER- UND C-FILES FÜR DIE SFUNCTIONS 19

6.4.2 @simulink ctor - Constructor

MyType_s* ctor_MyType(ObjectJc* othiz, float Tstep, int ObjId, float arg1, int arg2);

• Die zugehörige struct muss mit union { Object object; } base; beginnen. Der Speicherplatzwird in den Sfunction dynamisch angelegt. Für die Codegenerierung wird diejenige Zeile für Spei-cherplatzallokierung gerufen, die in Subtextvar genAllocmem im Generierscript angegeben wird,siehe 9.1 Seite 47. Es ist also ein anwendergestalteter Spezialalgorithmus möglich wenn nicht mitmalloc beim Bau des Systems gearbeitet werden soll.

• Alle Argumente sind non-tunable Parameter der Sfunction.

• float Tstep bewirkt die Zurordnung einer Abtastzeit über einen Parameter. Die Abtastzeit solltedann auch im Constructor in den Daten gespeichert werden, da sie häufig für die Berechnung vonzeitbezogenen Werten benötigt wird.

• Die int ObjId kann man sinnvoll nutzen, um Instanzen zu identifizieren. Der Verteilungsschlüsselobliegt dem Anwender. Die getIdentInfo_ObjectJc(...) wird in den emC-Library-Sources undsollte auch in der Anwendung nicht algorithmisch verwertet werden, sondern ist nur eine Hilfe beider Datenauswertung. Die Intension hierbei ist: Hat man einen Speicherauszug, dann kann mandarüber feststellen, welcher Instanz diese Daten zuordenbar ist. Die Id kann also im Rahmen derAnwendung relativ frei vergeben werden. Zu beachten ist: Sehr große Datenstrukturen (16 MByte)können nur Id von 1...31 speichern. Die Id von Strukturen bis 1 Myte soll sich im Bereich 32..255bewegen, wenn 1..31 für große Strukturen reserviert ist. Normalkleine Strukturen bis 64 kBytesollten dann ab 256 numeriert werden, bis 4095.

• Die Argumentwerte werden im Simulink intern als double übergeben, werden aber im Sfunction-Wrapper geeignet gecastet.

• Der Constructor kann keine Aggregationen entgegennehmen. Dazu ist die @simulink init.-Routine da. Allgemein: Es müssen zuerst alle Instanzen angelegt sein, bevor sie verdrahtet wer-den. Anders ist dies nur bei manueller Programmierung möglich. Im UML-Sinn: Composites sindInstanzen, die vom jeweiligen Object selbst angelegt werden, also hier im Constructor. Dies istmöglich, wird außen nicht verdrahtet. Composites können aber als Aggregationen außen verwen-det werden. Sie werden in der @simulink init.-Routine als Output geliefert. Die Verdrahtung derAggregationen ist also immer Sache der Nachinitialisierung nach dem Constructor.

Page 20: Simulink objektorientiert mit C-Kernfunktionen - Anleitung mit Demo- / Test-Version · 2019. 1. 2. · Simulink objektorientiert mit C-Kernfunktionen - Anleitung mit Demo- / Test-Version

6 GESTALTUNG DER ANWENDER-HEADER- UND C-FILES FÜR DIE SFUNCTIONS 20

Ausprogrammierung des Constructor:

#ifndef __DONOTUSE_REFLECTION__

#include <Ctrl/genRefl/pid_Ctrl.crefl>

#else

char const reflection_PID_Ctrl_s[] = "REFL_PID_Ctrl";

#endif

PID_Ctrl_s* ctor_PID_Ctrl(ObjectJc* othiz, float Tstep)

{

PID_Ctrl_s* thiz = (PID_Ctrl_s*)othiz;

initReflection_ObjectJc(othiz, othiz, sizeof(PID_Ctrl_s), &reflection_PID_Ctrl_s, 123);

thiz->Tstep = Tstep;

//? setInitialized_ObjectJc(&thiz->base.obj);

return thiz;

}

• Die Reflection sind automatisch generiert und stehen als *.crefl-File (C-File mit const-Definitionen)passend bereit. Im gezeigten Beispiel unter emc/source/Ctrl/genRefl/*. Für eigene struct inSfunction stehen diese dort, wo sie laut Generierscript, siehe 9.1 Seite 47, erzeugt wurden.

• Das Anwendersystem (Target) kann den Reflectionzugriff ebenfalls direkt unterstützen. Alternativ,für ein kleines Targetsystem, wird die Ersatzlösung mit gesetztem Compilerschalter __DONOTUSE_REFLECTION__compiliert. Dann ist auch die Routine initReflection_ObjectJc(...) entsprechend abgestimmt,indem emc//sourceApplSpecific/applConv/ObjectJc_simple.h includiert wird, siehe File .../TagetNumericSimple/applstdef_emC.h.

• Die Routine initReflection_ObjectJc(...) erzeugt eine Exception wenn die Speichergrößennicht stimmen. Das ist eine Sicherheit. Ein entsprechendes TRY-CATCH ist im Sfunction-Wrapperenthalten und gibt eine Simulink-Fehlermeldung aus. Im Anwendersystem kann dieser Fakt ent-weder ignoriert werden (well-tested) oder ebenfalls mit TRY-CATCH gearbeitet werden.

• setInitialized_ObjectJc muss und darf nur gerufen werden, wenn es keine init-Routine gibt,siehe folgend. Der Nachverarbeitung wird damit angezeigt, dass diese Instanz fertig gebaut ist,mit allen Aggregationen.

Page 21: Simulink objektorientiert mit C-Kernfunktionen - Anleitung mit Demo- / Test-Version · 2019. 1. 2. · Simulink objektorientiert mit C-Kernfunktionen - Anleitung mit Demo- / Test-Version

6 GESTALTUNG DER ANWENDER-HEADER- UND C-FILES FÜR DIE SFUNCTIONS 21

6.4.3 @simulink init - Verbindung von Modulen, Aggregierung, Nachinitialisierung

/**init Comment

* @simulink init.

*/

void init_MyType(MyType_s* thiz, MyAggr_s* aggr

, float arg_param, float arg,

, MyBusType* arg_bus, , MyBusType* arg_cbus,

, MyComposite_s** comp_y

, MyBusType* arg_ybus, MyBusType* arg_ycbus);

Die init-Routine übernimmt die Verdrahtung der FB zu anderen FB. Die init-Routine wird im Simulinkeiner getrennten Abtastzeit zugeordnet, Tinit, und wird damit bei der Codegenerierung des SImulinkin einer eigenen step_...-Routine gerufen. Im Anwendersystem (Target) muss diese generierte step-Routine in einer Schleife mehrfach gerufen werden, siehe 12, Seite 63.

• Type* aggr: Alle Zeigertyp-Argumente außer Strings im Namen ohne _y... und ohne _bus sindInput-Connectoren des FB, die der Tinit-Abtastzeit zugeordnet sind. Das sind die Aggregatio-nen des Object-FB zu anderen Object-FB. Es sind in der Reihenfolge die obersten Eingänge. ImSimulink werden dafür Handle-werte als uint32 übergeben, siehe dazu ??, Seite ??. Sie müssenvon entsprechenden Outputs der typrichtigen FB versorgt werden, von den thiz-init-Ausgängenoder Composite-Ausgängen. Das sind die obersten Ausgänge des FB in der Grafik in der Tinit-Zeitscheibe. Die Typrichtigkeit wird im Sfuction-Wraper vor Aufruf dieser Routine getestet, überdie Reflection-Info im ObjectJc. Im Zielssystem (Target) wird die Typrichtigkeit als getestet vor-ausgesetzt, da das Modell vor der Codegenerierung mindestens einmal ausgeführt sein sollte. Eskönnen auch abgeleitete Instanzen verdrahtet werden, siehe TODO.

• float arg_param: Alle Argumente die auf _param enden, sind non-tunable Parameter der S-Function, sind also den Constructor-Argumenten gleichgesetzt. In welcher Routine sie übergebenwerden, hängt vom der Gestaltung der internen Programmierung ab. Wenn man diese Werte nur inder init-Routine benötigt, zusammen mit den Aggregationen, dann sind sie hier zweckmäßig undbrauchen nicht gespeichert werden. Es sind skalare Typen und Strings zulässig, keine anderenZeigertypen.

• float arg: Alle anderen skalaren Argumente sind Inputs, die aber in der Tinit-Zeit verarbeitetwerden. Es sind hier insbesondere berechnete Initialwerte verdrahtbar, aus Ausgängen andererFBs in der Tinit-Abtastzeit. Zu beachten ist, dass Änderungen dieser Werte nach der Initialisierungnicht mehr übernommen werden.

• Type** comp_y: Alle Zeigertyp-Argumente im Namen ..._y sind Output-Connectoren des FB fürinterne Composites. Composites sind Sub-Daten der Instanz, dessen Referenz nach außen ge-geben wird. Sie sind Composites, da sie der Tinit-Abtastzeit zugeordnet sind. Es sind in derReihenfolge die unteren Ausgänge nach Ausgängen der Tstep-Routine. Die Compoisites könnenanderen FB als Aggregation dienen. Hinweis: Die C-Routine muss einen Zeiger auf einen per-sistenten Speicherbereich ausgeben. Der Zeiger wird im Sfunction-Wrapper dann in ein Handleuint32 gewandelt und entsprechend in die globale Handle-Pointer-Tabelle eingetragen. Der Zeigermuss mit der Zuweisung *out_y = addr; belegt werden.

• Alle Zeigerargumeente mit _bus, _cbus _ybus oder _ycbus sind Bus- In- und Outputs die in derTinit-Zeit verarbeitet weden, also für berechnete Intialwerte in Bussen.

• Die Ein- und Ausgänge, die von diesen Argumetenten gebildet werden, sind in der Argumentrei-henfolge der oberen im FunctionBlock. Sie sind der Tinit-Abtastzeit zugeordnet.

Page 22: Simulink objektorientiert mit C-Kernfunktionen - Anleitung mit Demo- / Test-Version · 2019. 1. 2. · Simulink objektorientiert mit C-Kernfunktionen - Anleitung mit Demo- / Test-Version

6 GESTALTUNG DER ANWENDER-HEADER- UND C-FILES FÜR DIE SFUNCTIONS 22

Ausprogrammieren und Realisierung der Init-Routinen:

Die Konvertierung der Handle-In-und Output für die Aggregationen zu den tatsächlichen Speicheradres-sen der referenzierten Objekte wird im Sfunction-Wrapper erledigt. Damit spielt dieser Algorithmus keineRolle für die Anwenderprogrammierung und ist auch nicht im Zielsystem (Target) präsent.

/**init Comment

* @simulink init.

*/

void init_MyType(MyType_s* thiz, MyAggr_s* aggr

, float arg_param, float arg,

, MyBusType* arg_bus, , MyBusType* arg_cbus,

, MyComposite_s* comp_y

, MyBusType* arg_ybus);

Aufruf der Init-Routinen in der Sfunction und im Zielsystem:

Page 23: Simulink objektorientiert mit C-Kernfunktionen - Anleitung mit Demo- / Test-Version · 2019. 1. 2. · Simulink objektorientiert mit C-Kernfunktionen - Anleitung mit Demo- / Test-Version

6 GESTALTUNG DER ANWENDER-HEADER- UND C-FILES FÜR DIE SFUNCTIONS 23

6.4.4 step-Routine, Definition eines Object-FB: @simulink ObjectFB.

Ein Object-FB wird dann angelegt, wenn die so gekennzeichnete Routine im Header erkannt wird:

/**Routine determines port properties

* @simulink Object-FB, no-thizInit, no-thizStep, step-in, step-out, accel-tlc.

*/

char const* step_MyObjectFB(MyType_s* thiz,

, float arg_param, float arg,

, MyBusType* arg_bus, , MyBusType* arg_cbus,

, MyAssociation_s* assc

, MyBusType* arg_ybus, MyBusType* arg_ycbus

, MyOutAssociation_s* assc_y

);

Page 24: Simulink objektorientiert mit C-Kernfunktionen - Anleitung mit Demo- / Test-Version · 2019. 1. 2. · Simulink objektorientiert mit C-Kernfunktionen - Anleitung mit Demo- / Test-Version

6 GESTALTUNG DER ANWENDER-HEADER- UND C-FILES FÜR DIE SFUNCTIONS 24

6.4.5 @simulink defPortTypes - Routine für Port-Typedefinitionen aus Parametern

Sowohl für die Bestimmung der Porteigenschaften aus Parametern, als auch für die Bestimmung ein-zelner Porteigenschaften aus anderen vom Modell bestimmten Porteigenschaften kann der Anwendereine Routine bereitstellen:

/**Routine determines port properties

* @param defPortTypes contains array reference and length of array.

* @simulink defPortTypes.

*/

inline char const* definePorts(DefPortTypesJc* defPortTypes, EDefPortTypesJc cause

StringJc arg1, StringJc arg2_param)

{

Entry_DefPortTypeJc* portTypes = defPortTypes.ref;

portTypes[defPortTypes->ixOutputStep] = portTypes[0]; //Set output like input.

portTypes[defPortTypes->ixOutputStep].newDefined = 1;

return null; //no error.

}

Die C-Routine ist mit der Kennzeichnung@simulink defPortTypes als solche markiert. AlsArgument wird jedenfalls DefPortTypesJc* ... er-wartet. Diese struct enthält ein Array vom TypEntry_DefPortTypeJc.

Die Routine kann weitere Argumente ent-gegennehmen. Das sind in diesem BeispielText-Parameter mit 'StringJc' als Zeiger aufchar const* und die Länge übergeben. Auch nu-merische Parameter sind zulässig. Die Parametermüssen gleichnamig im @simulink ctor oder inder @simulink init-Routine verwendet werden.Das ist zweckmäßig, damit die selben Werte auchdort verarbeitet werden können, aber notwendigdamit die Parameter als solche erkannt werden.

Diese Routine wird nun im generierten Sfunction-Wrapper an mehreren Stellen benutzt:

=> Vor der Initialisierung der Ports wird in derSfunction-Wrapper-RoutinemdlInitializeSizes(...)

diese Routine mit einem leeren ArrayEntry_DefPortTypesJc gerufen. Das Argumentvon Typ EDefPortTypesJc wird mit

• kSetFromArg_EPropagatePortTypesJc

besetzt. Aufgrund der weiteren Parameter kannnun der Typ der Ports aus den Parametern ermit-telt werden. Die Ports werden dann erst gar nichtDYNAMICALY_... angelegt sondern so wie angege-ben.

=> Diese gleiche Routine wird mit

• kSetType_EPropagatePortTypesJc

• kSetSize_EPropagatePortTypesJc

• kSetComplex_EPropagatePortTypesJc

gerufen, wenn nach dem Aufruf derSfunction-Wrapper-Routinen mdlSetInput- undmdlSetOutputPortDataType(...) usw. die Rou-tinen

• mdlSetDefaultPortDataTypes(...)

• mdlSetDefaultPortDimensionInfo()

• mdlSetDefaultPortComplexSignals()

gerufen werden. Die entsprechenden Eigenschaf-ten der Ports aus dem Modell sind dann be-reits bekannt und den betreffenden Ports zuge-ordnet. Das Array vom Typ Entry_DefPortTypeJc

wird vorbelegt mit den bisher definierten Port-Typ-Informationen. Es können dann alle Ports oder be-stimmte Ports neu definiert werden, also typischer-weise Ausgänge in Abhängigkeit von den Ein-gangstypen. Es werden dann nach der Routine diePorts gesetzt, für die die Datenzelle newDefined

auf 1 gesetzt ist. Das müssen also alle bisherDYNAMICALLY_... definierte sein, und können auchweitere Ports sein. Nach Durchlauf der Routinewerden dann die erwünschten Ports gesetzt. Gibtes dann noch Widersprüche, dann meldet dieSimulink-Engine einen Fehler.

Page 25: Simulink objektorientiert mit C-Kernfunktionen - Anleitung mit Demo- / Test-Version · 2019. 1. 2. · Simulink objektorientiert mit C-Kernfunktionen - Anleitung mit Demo- / Test-Version

6 GESTALTUNG DER ANWENDER-HEADER- UND C-FILES FÜR DIE SFUNCTIONS 25

6.4.6 @simulink defTlcParam - Bestimmung von CodeGenerier-Parametern

Der Simulink- oder Embedded Coder liest non-tunable Parameter aus dem Modell im tlc-File überSFcnParamSettings.name_param. Die Werte derParameter, genauer Key-Werte-Paare müssen inder Sfunction über die Routine mdlRTW geschriebenwerden, mit Aufruf von ssWriteRTWParamSettings,siehe Help in Mathworks/Simulink. Ohne die hierbeschriebene Routine wird im Sfunction-Wrappergeneriert, dass alle non-tunable Parameter, diesich aus den Argumenten der ctor-, init-, step-Routinen ergeben, mit ihren aktuell im Modell para-metrieren Werten gespeichert werden. Diese kön-nen dann bei der Codegenerierung gesteuert vomtlc-File verwendet werden.

Die hier beschriebene Routine liest sowohl die

Port-Information aus der Modellverdrahtung der je-weiligen Sfunction als auch kann alle Parameterverarbeiten und als Key-Value-Paar ablegen. Infor-mationen aus der Laufzeit, beispielsweise Werteaus anderen FBlocks, sind nicht verfügbar. Es istmöglich, in der hier beschriebenen Routine Werteaus einem File einzulesen, der zuvor in der Runti-me des Modells aus Runtimewerten geschriebenwurde, somit sind diese Informationen erhältlich.Man hat mittels dieser Routinen die freie Auswahlfür alle möglichen Parameter des jeweiligen FBlockfür die Codegenerierung. Nutzbar ist dies speziellfür Sonderfälle, bei denen der tlc-File des Blockty-pes selbst geschrieben wird. Genutzt ist das bei-spielsweise bei den FBlocks aus der lib_Inspc:get_Access_DataStruct_Inspc.

/**Routine to determine .....

* @return number of chars used in buffer_tlcParam.

* @simulink defTlcParam_excl.

*/

int defTlcParams_Access_DataStruct_Inspc(DefPortTypes_emC* portInfo_tlcParam

, char const* keys_tlcParam[5], char const* values_tlcParam[5]

, char buffer_tlcParam[500], int zBuffer_tlcParam

, char header_param[200]

, StringJc typeDataIn_param

, char datapath_param[200]

, StringJc typeOut_param

, StringJc name_param

);

Die Kennzeichnung defTlcParam_excl gegenüberdefTlcParam bedeutet, dass nur die hier vorge-sehenen Parameter in mdlRTW(,,,) übergegebenwerden. Ansonsten sind die hier gebildeten Para-meter zusätzlich zu den ohne diese Routine sonstübergebenen Parametern.

Alle Argumente deren Namen auf _tlcParam en-den, sind so wie genannt zu schreiben. Sie habenfolgende Bedeutung:

• portInfo_tlcParam Info über die Port-eigenschaften aus dem Modell, es wirddie Routine static void setPortInfo(

simstruct, portInfo_tlcParam,

kRun_EPropagatePortTypes_emC) aufgeru-fen, die im SfunctionWrapper spezifisch ge-neriert wird.

• keys_tlcParam[SIZE] Das Array wird mit

der direkt konstant angegebenen SIZE imStack angelegt. In der Routine werden dieKeys als Namen der Parameter als "NAME"fürSFcnParamSettings.NAME dort gespeichert.

• values_tlcParam[SIZE] Adäquat werdenhier die Zeiger auf die Value-Texte gespei-chert. Die Texte dürfen im Stack stehen, ins-besondere entweder direkt aus den weite-ren Argumenten entnommen werden oder imbuffer_tlcParam aufbereitet werden. Die SI-ZE muss identisch sein.

Hinweis: In C(++) bedeudet die Definitionchar* ARG[123] lediglich die Definition ei-nes char**. Die Arraygröße kann nicht ver-wertet werden, auch nicht mit sizeof(ARG)und stellt lediglich einen Kommentar dar.Für die Sfunction-Wrapper-Generierung wirdaber genau diese Information benutzt, um für

Page 26: Simulink objektorientiert mit C-Kernfunktionen - Anleitung mit Demo- / Test-Version · 2019. 1. 2. · Simulink objektorientiert mit C-Kernfunktionen - Anleitung mit Demo- / Test-Version

6 GESTALTUNG DER ANWENDER-HEADER- UND C-FILES FÜR DIE SFUNCTIONS 26

den Aufruf ein entsprechendes Array der an-gegebenen Größe anzulegen. In der Routinedarf der Index sich dann nur in diesem Be-reich bewegen.

• buffer_tlcParam Buffer für die Aufbereitungvon textuellen Parameterwerten. Der Bufferwird mit der hier angegebenen Göße imSfunction-Wrapper im Stack angelegt und mit= {0} gefüllt.

• zBuffer_tlcParam Dieses Argument wird imSfunctionWrapper mit genau der angegebe-nen Größe des buffer_tlcParam belegt. Esist damit in der Routinen als Argument ver-fügbar. Damit werden Fehler vermieden dieenstehen könnten, wenn sich die Prototypde-finition im Headerfile, für die Größenangabeverwendet, und die Funktionsdefinition im c-File unterscheiden. Dies wird nicht vom Com-piler detektiert. Der Programmierer könnteauf eine falsche Größe achten, was zu fata-

len Laufzeitfehlern wegen Stackstrukturzer-störung führen könnte. Mit der Nutzung die-ses Argumentes sind die Bedingungen klardefiniert.

Die weiteren Argumente müssen in Typ und Na-men mit einem Argument im @simulink ctor, initoder Object-FB übereinstimmen. Extra Parameterwerden hier nicht erkannt. Die Parameter werdenfür den Aufruf der Sfunction bereitgestellt, gelesenmit ssGetSFcnParam(...). StringJc-Argumentewerden konstant mit 100 Zeichen Speicherplatz imStack angelegt. Mit der Angabe char NAME[SIZE]

ist der Platz für einen Parameterwert bestimmbar.Ist der tatsächlich Parameterwert länger, dann wirdabgeschnitten. Das ist das gleiche Verhalten wiebei den Parameter-Argmenten der anderen Routi-nen. Die Anzahl der erwartbaren Zeichen für einenParameter sollten aber im Kontext der Sfunctionbekannt sein.

Abbildung 2: Parameterdialog-Beispiel für Nachbearbeitung mit @simulink defTlcParam_excl

Das Bild zeigt den Parameterdialog für das obige Beispiel des SFblock getData_Access_DataStruct_Inspc.Die Parameter sind zumeist kurze Strings.

Page 27: Simulink objektorientiert mit C-Kernfunktionen - Anleitung mit Demo- / Test-Version · 2019. 1. 2. · Simulink objektorientiert mit C-Kernfunktionen - Anleitung mit Demo- / Test-Version

6 GESTALTUNG DER ANWENDER-HEADER- UND C-FILES FÜR DIE SFUNCTIONS 27

6.4.7 Weitere @simulink ..., Annotation.

• dtor: Descructor, wird in Simulink in dermdlTerminate(...) eines Object-FB gerufen

• Object-FB: C-Funktion als step-Routine ei-nes Object-FB. Diese Funktion wird als S-Funktion generiert mit den davor aufgefunde-nen ctor, dtor, init queryOutputPorts.

• Operation-FB: C-Funktion als step-Routineeines Operation-FB. Diese Funktion wird alsS-Funktion generiert

• accel-tlc: Zusatzkennung für einen Object-FB oder Operation-FB: FlagSS_OPTION_USE_TLC_WITH_ACCELERATOR wirdin der mdlInitializeSizes(...) gesetzt.

• no-thizInit: Zusatzkennung für einenObject-FB: Es wird kein Ausgang für dasthiz-Handle der Tinit-Zeitkonstante, also fürAggregationen, erzeugt. Dieser Object-FB istnicht für Aggregationen vorgesehen.

• no-thizStep: Zusatzkennung für einenObject-FB: Es wird kein Ausgang für das thiz-Handle der Tstep-Zeitkonstante erzeugt. Eswird damit bestimmt, dass dieser Object-FBkeine weiteren Operation-FB hat. Er kann

aber entweder als Aggregation verwendetwerden, oder er hat nur numerische Ausgän-ge oder ist eine Datensenke (sink ), beispiels-weise für die interne Ablage von Daten.

• step-in: Zusatzkennung an Object-FB: Eswird ein Eingang angelegt, der nur für dieOrganisation der Abtastreihenfolge zustän-dig ist. Der Eingang wird nicht in der Sfunc-tion verwendet und daher bei der Compilie-rung wegoptimiert. Siehe Kapitel 7.1, Seite40.

• step-out: Zusatzkennung an Object-FB: Eswird ein Ausgang angelegt, der nur für dieOrganisation der Abtastreihenfolge zustän-dig ist. Der Ausgang wird nicht in der Sfunc-tion verwendet. Er führt eine 0 und wird beider Compilierung dann wegoptimiert, wenner nur auf ungenutzte Eingänge geführt ist.Siehe Kapitel 7.1, Seite 40.

• try-catch: Für update und Operation/Object-FB: Die Abarbeitung wird in TRY-CATCH ge-hangen. Damit wird die Abarbeitung etwaslangsamer, nicht für kleine schnelle Routinennutzen. (ca. 50 ns).

Page 28: Simulink objektorientiert mit C-Kernfunktionen - Anleitung mit Demo- / Test-Version · 2019. 1. 2. · Simulink objektorientiert mit C-Kernfunktionen - Anleitung mit Demo- / Test-Version

6 GESTALTUNG DER ANWENDER-HEADER- UND C-FILES FÜR DIE SFUNCTIONS 28

6.5 Schreibweise der Argumente der relevanten C-Funktionsprototypen

Für die Schreibweise der Argumente gibt es Re-geln:

• thiz: Alle Funktionsdefinitionen müssen alserstes Argument den thiz-Zeiger erhalten.Das ist der Zeiger auf die Instanz- oderObject-Daten. thiz entspricht dem this inC++. Es wird hier mit z geschrieben, da zurCompilierung häufig ein C++-Compiler be-nutzt wird. Aus Sicht von C++ handelt es sichhier aber um eine normale Variable, this istals C++-keyword reserviert.

• othiz: Ausnahme: Der @simulink ctor sollals erstes Argument einen ObjectJc* othiz

erhalten. Dann muss aber der Typ der zu-gehörigen Daten als Zeigertyp des Rückga-bewertes definiert sein. Ein Constructor darfaber auch den typrichtigen thiz erhalten,dies ist für die Simulink-Generierung zuläs-sig, entspricht aber nicht den Regeln der ob-jektorientierten C-Programmierung mit emC.

• Type*: Zeigertypen werden in Simulink aufder Sfunction-Ebene als Handle-Inputs oderHandle-Outputs realisiert, wenn der Namedes Arguments nicht auf _bus endet. Hand-les sind 32-bit uint32 und werden Sfunction-intern über eine Zuordnungstabelle mit denAdressen ersetzt, bevor die eigentliche C-Kernfunktion gerufen wird. Für die Codege-nerierung auf 32-Bit-Zielsysteme werden anselber Stelle dann direkt die Speicheradres-sen weitergegeben.

• ctor( ...args): Alle Argumente des Con-structor @simulink ctor sind non-tunableParameter des FB in Simulink. Daher sindhier keine Zeiger zulässig sondern nurskalare numerische Werte oder Texte alsStringJc-Typ. Die Parameter sind in Si-mulink nicht tunable sondern sind mit derstartup-Phase fest.

• ctor( ...Tstep): Das Argument Tstep

des Constructors bestimmt als Simulink-Parameter die Abtastzeit des FB. Es mussein float oder double sein. Der Wert derAbtastzeit kann zweckmäßig in den Intern-daten (thiz) gespeichert werden, mussaber nicht. Der Parameterwert wird in dermdlInitializeSizes(...) der Sfunction

eingelesen und den Ports zugeordnet. Wennkein Tstep-Argument angegeben wird, dannwird die Abtastzeit aus den Input-Ports dieden Aufrufargumenten der step-Funktion zu-geordnet sind bestimmt. Alle Inputports derstep-Funktion müssen aus der selben Ab-tastzeit versorgt werden.

• TODO: Das Argument TstepOffset desConstructors bestimmt die Scheibe (Slice)in die der FB in die Abtastzeit eingen-ordnet wird. In der Sfunction in Simulinkwird ssSetOffsetTime(...) damit aufgeru-fen. Man kann FBs mit der gleichen unter-setzten Abtastzeit in Simulink in verschiede-ne Scheiben einordnen. Für die Codegene-rierung aus Simulink für das Zielsystem wirdfür jede Scheibe eine eigene step-Funktiongeneriert. Diese kann dann im Zielsystemebenfalls untersetzt aufgerufen werden.

• String-Parameter dürfen beim Construc-tor und @simulink init angegeben wer-den, und zwar mit der TypkennzeichnungStringJc. Dieser Typ in Fwc/fw_String.h

definiert enthält den const char* zeiger unddie Länge des Strings. Die Weiterverarbei-tung kann im normalen C erfolgen. DieÜbergabe von const char* direkt, als 0-terminierter String wie im Standard-C üblich,ist derzeit (Stand 2017-10) nicht vorgesehen.

• Numerische Parameter werden als double imParameterfeld der Sfunction notiert, werdenaber vor der Übergabe in den Ziel-typ gecas-tet.

• Zeigertyp-Argumente des @simulink init

die nicht auf _bus oder _ybus enden, sindwerden als Handle-Inputs (uint32) der Tinit-Zeitkonstante des damit gebildeten Object-FB umgesetzt. Das sind die Argumente fürAggregationen.

• Alle anderen Argumente des @simulink init

werden wie bei einem @simulink Object-FB

behandelt, aber in der Tinit-Zeitscheibe.Insbesondere können _param angegebenwerden, aber auch numerische Inputsund Outputs oder _bus Inputs und _ybus-Outputs. Die init-C-Funktion wird nur solan-ge zyklisch aufgerufen, bis intern das Flag

Page 29: Simulink objektorientiert mit C-Kernfunktionen - Anleitung mit Demo- / Test-Version · 2019. 1. 2. · Simulink objektorientiert mit C-Kernfunktionen - Anleitung mit Demo- / Test-Version

6 GESTALTUNG DER ANWENDER-HEADER- UND C-FILES FÜR DIE SFUNCTIONS 29

isInitialized((ObjectFB*)thiz) gesetztist. D.h. die Inputs- und Outputs müssenentweder aus Konstanten gebildet werden,auch aus einem Bus aus Konstantwerten,für Parametrierungen, oder von anderenObject-FB stammen aber mit Lieferung derAggregations-Zeiger auch geliefert sein. Fürden generierten Code des Zielsystems wirddie init-Routine nur beim Hochlauf mehrfachaufgerufen.

• Argumente für @simulink init, die auf_param enden, sind non-tunable Parameterder damit gebildeten Sfunction.

• Argumente für @simulink Object-FB oder@simulink Operation-FB die auf _param en-den, sind tunable Parameter der damit gebil-deten Sfunction.

• Werden bei step...() Zeiger von nicht-Skalartypen verwendet, deren Argument-Name nicht auf _bus endet, so sind dies fürdie FBs in Simulink Handle. Der Handlewertwird aber in der Tstep-Zeit verarbeitet undkann beispielsweise zwischen mehreren FBsumgeschaltet werden oder auch 0 sein. ImUML-Sinne sind das Association, keine Ag-gregation.

• Zeiger von Nicht-Skalartypen, deren Namenauf _bus enden, werden für Simulink alsBus-Inputs umgesetzt. Der Typ muss al-so als @simulink bus gekennzeichnet seinund im Matlab als Bus-Typ exisitieren. Diestruct-Definition des Types muss auf 8-Byte-Alignment achten, das Speicherlayout desBusses im Simulink muss mit der Überset-zung in der S-Function übereinstimmen. Dasist wichtig, weil der Bus direkt als Zeigerübergeben wird, vergleiche auch _cbus imFolgepunkt. Eine Bus-Instanz wird im Si-mulink intern als Speicherbereich geführt.Der Kernfunktion sowohl in der Sfunction alsauch im generierten target-Code aus Simu-link wird ein Zeiger auf diesen Bereich typge-recht übergeben. Siehe Abschnitt 6.9, Seite35l

• Zeiger von Nicht-Skalartypen, deren Na-men auf _cbus enden, werden für Simulinkals Bus-Inputs umgesetzt. Die Buselemen-te werden dabei auf einen temporären Spei-cher im Stack umkopiert (memcpy(...)). Da-mit kann die Bus-Struktur und die struct in

der C-Realisierung auseinanderfallen. Es istauch möglich, dass die Reihenfolge geändertist, oder Elemente fehlen, typisch für Versi-onsdifferenzen. Es entsteht dabei kein Feh-ler, die nichtvorhandenen Elemente bleibenmit 0 besetzt.

• Zeiger von Nicht-Skalartypen, deren Namenauf _ybus enden, werden für Simulink alsBus-Outputs umgesetzt. Der Typ muss alsoals @simulink bus gekennzeichnet sein undim Matlab als Bus-Typ exisitieren. Eine Bus-Instanz wird im Simulink intern als Speicher-bereich geführt. Der Kernfunktion sowohl inder Sfunction als auch im generierten target-Code aus Simulink wird ein Zeiger auf diesenBereich typgerecht übergeben. Der Speiche-rinhalt wird gefüllt. Hinweis: Das Speicherab-bild des Busses in Simulink muss mit demSpeicherabbild in C übereinstimmen. Dieswird in der mdlInitializeSizes(...) ge-prüft. Zur Bildung der typedef struct [...}

für einem Simulink-Bus müssen die Regelndes Alignment beachtet werden, siehe Hin-weise in 6.1 Seite 14. Dies gilt auch für dieBus-Inputs. Siehe Abschnitt 6.9, Seite 35

• Numerische Skalartypen sind normale Input-Größen in Simulink. Die Skalartypen wer-den mit float, double, float_complex,double_complex, int32, uint32, int16,uint16, int8, uint8, boolean bezeichnet.Im C sind die nicht-Standard-Typen in einemHeaderfile compl_adaption.h definiert, sieheKapitel TODO. In Simulink werden die dazupassenden Simulink-Typen zugeordnet.

• Complex-Größen müssen in C mitfloat_complex und double_complex ge-kennzeichnet werden.

• Für numrische Inputs können Zeiger ver-wendet werden, um eindimensionale numeri-sche Vektoren zu verarbeiten.Entsprechendwerden im Simulink Vektor-Inputs der ange-gebenen Dimension erzeugt. Für C werdenVektoren bekannterweise als Zeiger über-geben. Der Speicherbereich der Vektorenliegt außerhalb. In C kann also auch zu-rückgeschrieben werden. Das Rückschrei-ben ist aber für Simulink so nicht vorgese-hen und funktioniert deshalb nicht, weil in derSimulations-Engine des Simulink die Vekto-ren möglicherweise auf eine Zwischenspei-

Page 30: Simulink objektorientiert mit C-Kernfunktionen - Anleitung mit Demo- / Test-Version · 2019. 1. 2. · Simulink objektorientiert mit C-Kernfunktionen - Anleitung mit Demo- / Test-Version

6 GESTALTUNG DER ANWENDER-HEADER- UND C-FILES FÜR DIE SFUNCTIONS 30

cher vor der Zeigerbildung umkopiert wer-den. Zurückschreiben auf Input-Vektoren imCode der Funktionen darf also nicht genutztwerden. Konsquenterweise sollten die Zeigerals float const* oder const float * ge-kennzeichnet werden. Dies wird nicht extrageprüft.

• Numerische Outputs der Object-FB undOperation-FB müssen als Zeiger realisiertwerden, und im Namen mit _y enden.

• Inputs mit dem Typ void const* werden alsDYNAMICALLY_TYPED und DYNAMICALLY_SiZED

angelegt. Entsprechend der angeschosse-nen Quelle in Simulink wird beim Modellstartund bei der Codegenerierung der Typ fest-gestellt. Der Typ und die Anzahl Elementewird in ein Array abgelegt, dass als Input mitdem Namen InputTypes_ übergeben wird.Damit wird der C-Funktion mitgeteilt welcheInputs aktuell verdrahtet sind. Die Auswer-tung obliegt der C-Ebene. Über diesen Wegkann eine C-Funktion beispielsweise Vekto-

ren mit verschiedenen numerischen Typenverarbeiten. Hinweis: Die back-propagationvon Outputs hierfür wird nicht unterstützt. Je-doch können Outputs aus den Eigenschaftender Input-Typen festgelegt werden, siehe fol-gend.

• Outputs mit dem Typ void* und der Namens-Endung _y müssen geeignet in C defi-niert werden. Dies kann abhängig von Pa-rametern geschehen. Dafür die C-Funktion@simulink queryOutputPorts vorgesehen.Dieser muss die Referenz auf ein Array vomTyp Entry_QueryPortTypeJc übergeben wer-den. Das Array wird gefüllt mit den vorgese-henen Typen der Outputs.

Die Codegenerierung für das Zielsystem aus Si-mulink legt die Speicherbereiche für Vektoren,Skalare Output-Werte und Busse nach einem Bus-Creator passend und richtig an und übergibt denC-Kernfunktionen wie erwartet die Zeiger auf die-se Bereiche.

Page 31: Simulink objektorientiert mit C-Kernfunktionen - Anleitung mit Demo- / Test-Version · 2019. 1. 2. · Simulink objektorientiert mit C-Kernfunktionen - Anleitung mit Demo- / Test-Version

6 GESTALTUNG DER ANWENDER-HEADER- UND C-FILES FÜR DIE SFUNCTIONS 31

6.6 Konzept der Handle, Handle_ptr64_emC.h

Diese ist so gebaut, dass für die SFunctions an dieser Stelle nur das Handle steht, als uint32-Wert.Im Zielsystem ist der Handle-Wert und die 32-bit-Speicheradresse identisch und wird daher als union

beider Bezeichner abgebildet. Der generierte Code aus Simulink kennt nur das Handle. Für den Zei-gerzugriff wird das Makro PTR_HandlePtr_emC(NAME) verwendet. Dieses greift im Zielsystem direkt aufden Zeigerwert zu, im S-Function-Code wird hier der Handle-Pointer-Mechanismus über die globaleZuordnungstabelle verwendet,

TODO

Page 32: Simulink objektorientiert mit C-Kernfunktionen - Anleitung mit Demo- / Test-Version · 2019. 1. 2. · Simulink objektorientiert mit C-Kernfunktionen - Anleitung mit Demo- / Test-Version

6 GESTALTUNG DER ANWENDER-HEADER- UND C-FILES FÜR DIE SFUNCTIONS 32

6.7 Ausprogrammierung der C-Funktionen, Reflection

Einfache C-Funktionen insbesondere für dieStep-Routine (@simulink Object-FB oder@simulink Operation-FB) sollten ihre wenigenAnweisungen als INLINE_Fwc erhalten und wer-den damit inline in den Maschinencode eingebaut.

Das ist effektiv.

Beim @simulink ctor oder @simulink init istdas so nicht notwendig, da es dabei nicht umschnelle Ausführung geht. Diese C-Funktionensollten also im C-Code realisiert werden.

Constructor mit ObjectJc-Basisstruktur, Einbindung der Reflection

#ifndef __DONOTUSE_REFLECTION__

#include "AngleBlocks_FB.crefl"

#endif

void ctor_Angle_abwmf_FB(Angle_abwmf_FB* thiz, int32 identObj)

{ memset(thiz, 0, sizeof(*thiz));

initReflection_ObjectJc(&thiz->obj, thiz, sizeof(*thiz),

&reflection_Angle_abwmf_FB, identObj);

thiz->m = 1.0f; //default for only-angle

setInitialized_ObjectJc(&thiz->obj);

}

Der obige Anwender-Code zeigt, wie das generier-te Headername.refl-File eingebunden wird. Das.refl-File enthält die const-Definitinen der Reflec-tions, ist also kein Header. Das File wird aber den-noch includiert und nicht eigenständig sondern hierübersetzt.

Das Includieren ist in bedingte Compilierung ge-schrieben, denn dieses selbe File soll auch ver-wendet werden für ein Zielsystem ohne Reflection.

Der Constructor wird vom Simulink in der Sfunctiongerufen mit allokiertem und vorinitialisierten Spei-cher. Die memset(...0...)-Operation ist also ei-gentlich nicht notwendig. Im Zielsystem sollte ad-äquat verfahren werden. Man kann statische mit 0intialisierte Instanzen sehr einfach mit

Angle_abwmf_FB instance = {0};

anlegen bzw. nach dem Allokieren den Speichersofort mit 0 initialisieren.

Der folgende Aufruf initReflection_ObjectJc(...)initialisiert die ObjectJc-Daten mit den notwen-digen Informationen. In einem einfachen Ziel-system, das keine Reflection verarbeitet und ei-ne ObjectJc-Basisstruktur auch nicht braucht,ist in der emC-Lib unter incApplSpecific / Targ-etNumericSimple / applstdefJc.h in der dort in-cludierten ObjectJc_simple.h eine Definition fürinitReflection_ObjectJc(...) enthalten, diedas &reflection_...-Argument ignoriert. Dannwird es auch nicht syntaktisch geprüft, muss alsonicht vorhanden sein. Damit wird ohne Quellände-rung die Kompatibilität von Quelltext für Sfunction,PC-Simulation und Zielsystem erreicht.

Constructor ohne ObjectJc-Basisstruktur

Wenn die struct nicht auf ObjectJc basiert, dann istder Constructor im einfachsten Fall leer. Er sollte

aber definiert werden, weil die Wrapper der Sfunc-tion den Constructor jedenfalls aufrufen.

Page 33: Simulink objektorientiert mit C-Kernfunktionen - Anleitung mit Demo- / Test-Version · 2019. 1. 2. · Simulink objektorientiert mit C-Kernfunktionen - Anleitung mit Demo- / Test-Version

6 GESTALTUNG DER ANWENDER-HEADER- UND C-FILES FÜR DIE SFUNCTIONS 33

Scharfe Prüfung der Daten beim Constructor

OrthOsc2_FB* ctor_OrthOsc2_FB(ObjectJc* othiz, int32 identObj, float kA, float kB)

{ OrthOsc2_FB* thiz = (OrthOsc2_FB*) othiz;

if(-1 != checkStrict_ObjectJc(othiz, (int32)sizeof(OrthOsc2_FB)

, ident_newAllocated_ObjectJc, null, null)){

initReflection_ObjectJc(othiz, thiz, sizeof(*thiz)

, &reflection_OrthOsc2_FB, identObj);

thiz->kA = kA;

thiz->kB = kB;

}

return thiz;

}

Wenn Software an bestimmten Stellen prüft ob Be-dingungen stimmen, dann werden eingeschliche-ne Fehler erkannt. Wird offensichtlich geprüft dannstehen die Bedingungen an dieser Stelle fest, oh-ne dass ein nochmaliger Blick auf das Gesamtsoft-waresystem notwendig ist. Das erleichtert auch dieErreichung eines erforderlichen SIL-Levels der Si-cherheitsrelevanten Software.

Dieses Beispiel zeigt die Übergabe nur desObjectJc-Zeigers an den ctor. Der Speicherbereichwird im Sfunction-Wrapper mit der richtigen Grö-ße allokiert und in den ObjectJc-Daten mit einerDefaultbelegung versehen. Diese umfasst:

• Die eigene Speicheradresse steht im Spei-cher

• Eine Size-Information wird abgelegt.

• Eine ident-Information= ident_newAllocated_ObjectJc wird ab-gelegt.

Im Zielsystem wird mit malloc-Nutzung ebenso ver-fahren. Werden die Daten im Zielsystem statischangelegt, dann kann man einen Initializer benut-zen:

OrthOsc2 myOrth = INITIALIZER_ObjectJc( myOrth, null, ident_newAllocated_ObjectJc );

Der INITIALIZER_ObjectJc(...) liefert die {...}

mit der richtig eingetragenen Initialbelegung, sieheemC/source/objectBaseC.h.

Die Abfrage checkStrict_ObjectJc(...) testetnun, ob der übergebene Zeiger einem Object-Jc entspricht. Dazu muss die Speicheradres-se mit der eigenen Adresse übereinstimmen,damit würde eine Verschiebung der Daten er-kannt. Die size-Info muss größer oder gleichder verlangten sizeof(*thiz) sein, und auch das

ident_newAllocated_ObjectJc muss eingetragensein. Damit handelt es sich um eine noch nicht ver-wendete Instanz der passenden Größe und dies istfür die weitere Verarbeitung wichtig. Man kennt jaProgramme, die ganz am Anfang Zeiger mal ver-wechseln, dann den falschen Speicherbereich mitrichtigen Daten überschreiben, dann funktioniert indiesem Modul erstmal alles korrekt. Der Fehler fälltan ganz anderer Stelle schwer debugbar auf. Daswird durch diese Verarbeitung verhindert.

Page 34: Simulink objektorientiert mit C-Kernfunktionen - Anleitung mit Demo- / Test-Version · 2019. 1. 2. · Simulink objektorientiert mit C-Kernfunktionen - Anleitung mit Demo- / Test-Version

6 GESTALTUNG DER ANWENDER-HEADER- UND C-FILES FÜR DIE SFUNCTIONS 34

Die init-Routine

void init_OrthOsc2_FB(OrthOsc2_FB* thiz, Param_OrthOsc2_FB* par, Angle_abwmf_FB* angle)

{

if( ! isInitialized_ObjectJc(&thiz->obj) && par !=null && angle !=null) {

//yet complete:

thiz->par = par;

thiz->anglep = angle;

setInitialized_ObjectJc(&thiz->obj);

}

}

Die mit @simulink init gekennzeichnete Routine übernimmt Aggregationen von anderen Sfunctions.Das Beispiel zeigt, dass beide Aggregationen auf nicht-null geprüft werden. Im Initialisierungslauf kannein mehrfacher Durchlauf der Initialisierung notwendig sein, wenn Aggregationen wechselseitig oderzirkular bestehen. Das ist teils notwendig. Dann werden erst im Folgedurchauf die Ausgangsportsbelegt, die für eine Aggregation einer Instanz davor benötigt werden. Die Ausgangsports bleiben be-legt, so dass mit wenigen Durchläufen die Aggregationen bereitstehen. Dann wird die Instanz aufisInitialized_ObjectFB() gesetzt. Diese Bedingung wird in der step-Abtastzeit der Instanz abgefragtin der DFunction im Simulink-Lauf abgefragt. Im Zielsystem wird die init-Routine mehrmals gerufen. EineAbfrage auf isInitialized_ObjectFB() erfolgt dort nicht wenn nicht in der Anwenderprogrammierungenthalten.

Gibt es keine @simulink init-Routine, dann muss das setInitialized_..(...) im Constructor ge-setzt werden, wie im obigen Beispiel für ctor_Angle... gezeigt.

6.8 Allokierung des internen Speichers

Die Zeiger, die als Handle geführt werden, sind im-mer Zeiger auf Interndaten. Diese werden in dengenerierten Sfunction-Wrapper der FBs in Simu-link über malloc angelegt. Sie werden auch im ge-nerierten Code für das Zielsystem über eine ange-gebenen Allokierungsfunktion angelegt, siehe Ka-

pitel 9 Seite 46, oder sie werden als statischerSpeicher im Zielsystem-Code pro Instanz angelegt(reentrant) und dann jeweils den C-Kernfunktionenals Zeiger übergeben. Gleiches gilt für den thiz-Zeiger und die Instanzdaten selbst.

Page 35: Simulink objektorientiert mit C-Kernfunktionen - Anleitung mit Demo- / Test-Version · 2019. 1. 2. · Simulink objektorientiert mit C-Kernfunktionen - Anleitung mit Demo- / Test-Version

6 GESTALTUNG DER ANWENDER-HEADER- UND C-FILES FÜR DIE SFUNCTIONS 35

6.9 Busse als Input und Output / 8-Byte-Alignment

Ein Bus im Simulink fasst Daten zusammen. Simu-link kennt mehrere Möglichkeiten der Datenbün-delung. Der non-virtual Bus wird dabei im gene-riertem Code immer von einer struct in einemHeader repräsentiert. Man kann im Simulink beider Busanlage wählen, ob die struct-Definition,bzw. der zugehörige Header Imported oder Ex-ported ist. Letzteres bedeuted, dass Simulink denHeader mit der Codegenerierung mit generiert. BeiImported wird ein Header angegeben, der im ge-nerierten Code includiert wird und vom Anwenderbeigestellt werden muss. In diesem Fall muss diestruct-Definition im Header weitgehend dem Busentsprechen. Es ist aus Simulink-Sicht nicht not-wendig, dass Anzahl und Anordnung der Datenele-mente übereinstimmen. Lediglich die verwendetenDatenelemente müssen in der struct auffindbarsein. Es ist in diesem Fall also etwas Freiheit derC-Gestaltung gegeben.

Die Mathworks-Dokumentationen beschreiben bei-de Varianten gleichermaßen. An einigen Stellenwird auf den Vorteil von Imported verwiesen. Es

wird eine nutzerfreundliche grafische Bedienungmit dem Bus Editor angeboten, der die Nutzungvon Exported zwar nahelegt, aber auch Impor-ted als Anwahl zulässt - hier wieder als Eigenver-antwortung des Programmierers, dessen struct-Definition dann passen muss.

Für das hier angebotene System der Program-mierung Kerne in C, Organisation in Simulinkist die Imported-Variante der Busse naheliegend.Mehr noch: Es wird die Generierung von Matlab-Script-Files für die Bus-Anlage im Simulink ausdem Header unterstützt. Die struct werden da-zu mit @simulink bus gekennzeichnet siehe Ab-schnitt 6.4, Seite 18.

Werden in einer C-Routine für Sfunction nicht-skalare Datentypen als Zeigerargumente verwen-det, dann wird ohne weitere Kennzeichnung dar-aus ein Handle gebildet. Das ist eine Referenz,kein Bus. Wenn als Input oder Output ein Bus ver-wendet werden soll, dann müssen die Namen derArgumente auf _bus bzw. _ybus enden, siehe Ab-schnitt 6.5, Seite 28.

Alignment der Daten in einer struct - direkte Buszeigerverwendung

In den Sfunction in Simulink, die mit demLegacy-Code-Tool von Mathworks generiert wur-den, wird nicht vorausgesetzt, dass die struct-Definition im Header mit der Bus-Definition ex-akt übereinstimmt. Daher wird bei diesen Sfunc-tions der Inhalt des Busses bei Aufruf umko-piert. Simulink bietet Framework-Routinen wiessGetBusElementOffset(...) an, um die Positi-on der Elemente im Bus im Speicher bei derSimulink-Abarbeitung zu ermitteln. Bei der hier vor-gestellten Sfunction-Generierung ist die Überein-stimmung von Bus und struct im Header jedochgegeben, wenn das Bus-Script nicht nach der Ge-nerierung geändert wird. Damit ist das Umkopierengrundsätzlich nicht notwendig.

Allerdings gibt es bestimmte Alignment-Regeln.Diese Alignment-Regeln sind aber nicht Simulink-spezifisch sondern treten häufig sogar noch ver-schärft bei der Codegenerierung für verschiede-ne Zielprozessoren auf. Nicht jeder Prozessor un-terstützt den Zugriff auf beliebige auch ungeradeAdressen. Selbst in der Intel-Technologie ist derZugriff auf beliebige Adressen mittlerweile nicht

mehr immer möglich: Wird der Speicher mit einem32-Bit oder 64-Bit-Datenbus angesprochen, dannist mindestens für einen sogenannten Atomic-Access der Aufwand höher, wenn etwa ein float-Wert über 2 Speicherwort verteilt liegt.

Daher sollte vom Anwender bei der Anlage vonstruct folgende Regel immer beachtet werden:Ein Datenelement muss in einer struct immerauf einer Adressposition liegen, die durch dieLänge des Datenelements teilbar ist. Also einfloat-Wert auf einer durch vier teilbaren Adresse.Wenn man diese Regel bei jeder struct-Definitioneinzeln anwendet, dann ist sie immer erfüllt. Zu-sätzlich kommt hinzu: Die Länge einer structmuss durch die Länge der Speicherbreite ge-teilt werden können. Das bedeutet, bei 64-Bit-Systemen durch 8. Geht man davon aus, dass diemeisten größeren Anwendungen auf einem Ziel-system laufen, dass nicht extrem speicherknappbemessen ist, dann kann man struct-Defintionengleich so anlegen, dass ihre Länge durch 8 teilbarist. Damit ist die Kompatibilität mit einem 64-Bit-System, insbesondere der Simulation auf dem PC,gewährleistet. Die Alignment-Regeln kann man

Page 36: Simulink objektorientiert mit C-Kernfunktionen - Anleitung mit Demo- / Test-Version · 2019. 1. 2. · Simulink objektorientiert mit C-Kernfunktionen - Anleitung mit Demo- / Test-Version

6 GESTALTUNG DER ANWENDER-HEADER- UND C-FILES FÜR DIE SFUNCTIONS 36

einfach dadurch erreichen, dass die Datenelemen-te etwas sortiert werden.

//falsch:

struct .... {

char c;

float val;

char c2;

}

//richtig:

struct ... {

float val;

char c;

char c2;

char spare[2];

}

Die beiden spare-Byte werden auf dem Zielsys-tem sowieso eingebaut, wenn das Zielsystem denZugriff nur auf volle Adressen zulässt. Es handeltsich also nicht um Speicher-Verschwendung, son-dern um Beachtung der Software-Stilregel be ex-plicit. Die struct-Länge ist damit durch 8 teilbar.Ist die Anwendung für ein speicherknappes 16-Bit-System vorgesehen und wird die struct nichtals Array-Element-Typ verwendet, dann brauchendie spare-Elemente nicht angegeben werden undwerden im Zielsystem auch nicht realisiert. Wirdder struct-Typ als Array-Element verwendet, dann

werden auf dem PC im Simulink oder auch im Ziel-system die Array-Elemente auf die Speicherbrei-te alignet. Die spare werden dann also automa-tisch doch wieder angelegt. Daher: be explicit! - imQuelltext sichtbar angeben. Dazu noch folgenderHinweis: Werden Daten als Speicherabzug aus ei-nem Zielsystem binär übertragen und auf dem PCdanach analyisiert, dann ist auch dafür die korrek-te Adressierung der Daten notwendig. Eine autoti-sche verschiedene Interpretation der Datenpositio-nen von verschiedenen Compilern / Zielsysteman-forderungen sollte nicht provoziert werden.

Wird die Alignment-Regel, insbesondere die durch8 teilbare struct-Länge nicht beachtet, dann kannes im Accelerator- und Rapid-Accelerator-Mode zueiner Fehlermeldung kommen:

Unexpected error: Internal BlockIO sizes

do not match for accelerator mex file.

Beim Start des Accelerator wird die Größe der ge-samten Daten-struct verglichen mit der angelegtenByteanzahl in der Simulation-Engine. Diese stimmtnicht überein bei einem Alignment-Problem, wasmit dieser Fehlermeldung gezeigt wird:

if ( ssGetSizeofGlobalBlockIO ( S) !=

sizeof ( B_TestOrthOscObjO_T ) )

{ ssSetErrorStatus( S, "Unexpected

Überprüfung der Richtigkeit der Bus-Abbildung mit der struct bei Aufruf der Sfunction

Bei den mit diesem System generierten Sfunc-tions wird nun bei der PC-Simulation der Busaus der Simulink-Anlage direkt als Zeiger denSfunctions übergeben. Das Umkopieren wie beiden Sfunction aus dem Legacy-Code-Tool ent-fällt. Damit aber gesichert ist, dass das Spei-cherabbild stimmt, wird dieses in der Sfunctionin mdlInitializeSizes(...) überprüft. Es wer-den die Namen und Positionen der Datenlementein struct und Simulink-Bus-Speicherabbild vergli-chen. Für die Namen und Positionen in der struct

werden dazu die Reflection-Informationen heran-gezogen. Für verwendete Zeigertypen als Bussemüssen also die Reflections in den S-Function mitangegeben werden. Die Reflection werden auto-tisch generiert, siehe 9.1, Seite 47.

Für den Code auf dem Zielsystem spieltdiese Problematik keine Rolle. Die Simulin-Codegenerierung verwendet die struct-Definitionder Busse im Imported-Header ohne eigene zu-sätzliche Interpretation.

Page 37: Simulink objektorientiert mit C-Kernfunktionen - Anleitung mit Demo- / Test-Version · 2019. 1. 2. · Simulink objektorientiert mit C-Kernfunktionen - Anleitung mit Demo- / Test-Version

6 GESTALTUNG DER ANWENDER-HEADER- UND C-FILES FÜR DIE SFUNCTIONS 37

6.10 Busse mit boolean-Elemente und Bitfields in struct-Definitionen

Die Verwendung von boolean-Elemente in Bussenfür Boolean-Verknüpfungen in Simulink-Modellenund die Abbildung der boolean als Bits in Bitfieldsist interessant und effektiv. Diese Thematik wirdauch für dieses System der S-Functions angebo-ten werden, mit folgender Herangehensweise:

* Keine Mischung von Bitfields in einer struct mitanderen Daten

* Der Bus enthält also nur boolean

* Mit geschachtelten Bussen (Bus im Bus, nested

struct) ist dann die Mischung möglich.

* Eine Kombination mit einer Wortabbildung derBits in einer union - Zugriff auch über Maskierung- ist empfohlen.

* Die Zuweisung zwischen Boolean im Bus undBit im Bitfield wird dann in der Sfunction im Simu-link per symbolischer Bezeichnung (Name des Ele-mentes) erfolgen.

* Im Zielsystem kein Problem

Diese Lösung ist derzeit (2017-12) in Erarbeitung

Page 38: Simulink objektorientiert mit C-Kernfunktionen - Anleitung mit Demo- / Test-Version · 2019. 1. 2. · Simulink objektorientiert mit C-Kernfunktionen - Anleitung mit Demo- / Test-Version

6 GESTALTUNG DER ANWENDER-HEADER- UND C-FILES FÜR DIE SFUNCTIONS 38

6.11 Dynamische Festlegung der Porttypen - EntryQueryPortTypesJc

In Simulink-Modellen ist es auch mit Sfunc-tions möglich, die Datentypen und Vektor-Dimensionen der Ports aus dem Modell her-aus festzulegen. Für die C-Ebene sind dasvoid*-getypten Argumente oder Zeigern aufArrays mit undefinierter Länge (float arg[ ]

und dergleichen). Für die Simulink-Ebene derSfunction-Programmierung gibt es für die Portsdie Kennzeichnung DYNAMICALLY_TYPED undDYNAMICALLY_SIZED sowie COMPLEX_INHERITED.In solchen Sfunction-Wrapper müssen Routinenwie mdlSetInputPortDataType(...port,id) ent-halten sein. Diese werden beim Modellstart vonder Simulink-Engine gerufen und teilen den an-geschlossenen Datentyp der Sfunction mit. Einweiterer Routinentyp in dem Sfunction-Wrapperist mdlSetDefaultPortDataTypes. In dieser Routi-ne kann man Ports bestimmen, die nicht von derVerdrahtung im Modell berücksichtigt sind oderPorts anders bestimmen, als es die Verdrahtungursprünglich ermittelt hat.

Im Modell kann der Typ der Ports sowohl alsforward-propagation von den Signalen an Input-Ports bestimmt werden, als auch als backward-propagation von den Signalen, die am Ausgangverlangt werden. Letzteres kann erfahrungsgemäßin einem Modell eher zu Widersprüchen führen, eswird daher davon abgeraten.

Der Typ von Ausgangsports kann auch vom Typ

der angeschlossenen Signale an Inputs abhän-gen. Dies ist eine häufige Situation. Berechnet bei-spielsweise eine Sfunction einen Wert aus ange-schlossenen Vektoren, dann können die Vektorele-mente float, double oder integer-Typen sein, auchkomplexe Größen. Die Resultate richten sich nachden Typen der Eingänge.

Die Codegenerierung wird nun für ein konkretesModell ausgeführt. Dabei stehen die Typen derEin- und Ausgänge, nach Durchlauf der oben ge-nannte Sfunction-Wrapper-Funktionen, fest.

Für die C-Ebene wird für diese Ports ein void*

oder ein Array-Zeiger eines numerischen Typs vor-gesehen. Bei angegebenem numerischen Typ istnur DYNAMICALLY_SIZED für das betreffende Portgesetzt. Es wird damit die Adresse der Daten über-geben. In der C-Funktion muss dann für den void*-Fall ein entsprechender Pointer-cast ausgeführtwerden.

Der C-Routine muss der Type der angeschlos-senen Signale bekannt sein, damit ein qua-lifiziertes Type-Casting möglich ist und/oderdie Array-Länge bekannt ist. Das geschiehtmit einer struct DefPortTypesJc, definiert inFwc/objectBaseC.h in der emC-Library. Ein sol-ches Array wird bei der Sfunction-Generierung an-gelegt, gefüllt mit den Port-Informationen aus demModell. Dazu ein Beispiel :

/**Example of a static routine with void* arguments which uses info about port types.

* @simulink Operation-FB.

*/

void copyArray_Example(DefPortTypesJc* portInfo, void const* input, void* output_y){

if(portInfo->entries[0].type == 'F') {

int ix;

for(ix = 0; ix < portInfo-entries[0].sizeArray[0]); ++ix) {

((float*)output[ix] = 5.0f * ((float*)input[ix];

}

}

}

Diese Routine definiert eine Sfunction mit zweiPorts. Diese werden mit DYNAMICALLY_TYPED an-gelegt. Wie folgend noch gezeigt wird, richtet sichaber der Typ und die Elementanzahl des Outputnach dem Input. Der Input hängt von der Verdrah-

tung im Modell ab. Die Routine überprüft nun, alsBeispiel, ob ein float-Wert (single im Simulink)angeschlossen ist und kopiert die Werte, als Bei-spiel mit 5.0 mulitpliziert.

Page 39: Simulink objektorientiert mit C-Kernfunktionen - Anleitung mit Demo- / Test-Version · 2019. 1. 2. · Simulink objektorientiert mit C-Kernfunktionen - Anleitung mit Demo- / Test-Version

6 GESTALTUNG DER ANWENDER-HEADER- UND C-FILES FÜR DIE SFUNCTIONS 39

Mitteilung der Port-Typinformation für die C-Routinen

Wenn der @simulink ctor, die init-Routineoder auch die Step-Routine ein Argument vomTyp DefPortTypesJc* verlangt, dann wird die-se struct im Stack angelegt, mit den In-formationen der Port-Indices gefüllt und dasgefüllte Array Entry_DefPortTypeJc bereitge-stellt mit den Port-Informationen. Die Routine@simulink defPortTypes wird nicht noch ein-mal gerufen, da die Ports bereits alle definiertsind. Nach der Codegenerierten für das Targetsind die Port-Informationen nur noch Konstante,die mit geringem Rechenzeitaufwand dargebrachtwerden können. Insbesondere im ctor oder inder init-Routine können aber die Portinformatio-nen in den Instanzdaten (thiz) geeignet gespei-chert werden. Das Beispiel in diesem AbschnittcopyArray_Example ist eine statische Operationohne Instanzdaten und braucht daher diese Infor-mationen direkt.

Ein Eintrag des Typ-Arrays EntryDefPortTypeJc

hat folgende Elemente:

• char type: Es werden für die numerischenTypen die Buchstaben F D I 4 S 2 B 1

für F=float D=double, I=int32 4=uint32,S=int16, 2= uint16, B=int8, 1= uint8 no-tiert. Die Buchstaben F D I S B entspre-chen den Java-Conventionen der Kurzbe-zeichnung der primitive-Types.

Für die komplexen Typen werden entspre-chende Kleinbuchstaben verwendet, al-so f=float_complex, d=double_complex

i=int32_complex, und s=int16_complex.Komplexe Zahlen als unsigned oder Byte

werden nicht unterstützt.

Eine '\0' an dieser Stelle bedeudet: Typenicht definiert, also DYNAMICALLY_TYPED.

• uint8 sizeType: Diese Information wird mitdem Typ zugehörig abgelegt, damit die An-wenderprogrammierung ohne Aufwand beimemcpy und dergleichen gleich die notwen-dige Byteanzahl kennt ohne die char type-Information auszuwerten.

• uint8 newDefined ist ein Eintragsplatz alsAufforderung, das Port zu definieren.

• uint8 nrofDimensions Enthält die Anzahlder Dimensionen. 0 definiert einen Skalar.

• uint32 sizeArray[5]: Ein Array kann imStandardfall bis zu 5 Dimensionen mit max.4000000000 Elementen enthalten. Das wirdin der Praxis sehr viel weniger sein. Wenndie Anzahl der Dimensionen nicht aus-reicht, dann wird ein extra Speicher fürsizeArray[...] vorgesehen und das Daten-element sizeArray[0] enthält den Zeiger aufdiesen Bereich. Es ist also mit cast zuzugrei-fen: (*(uint32**)sizeArray)[ix].

Es werden an dieser Stelle nicht die internenSimulink-Kennzeichnungen der Typen verwendet.Das erfolgt um die C-Programmierung eigentlichunabhängig von Simulink zu halten. Es müsstesonst das System der Simulink-Header includiertwerden und diese C-Programme hätten außerhalbder Simulink-Anwendung keinen Bestand.

Page 40: Simulink objektorientiert mit C-Kernfunktionen - Anleitung mit Demo- / Test-Version · 2019. 1. 2. · Simulink objektorientiert mit C-Kernfunktionen - Anleitung mit Demo- / Test-Version

7 ASPEKTE DER MODELL-GESTALTUNG 40

7 Aspekte der Modell-Gestaltung

7.1 Abarbeitungsreihenfolge

In der manuellen C-Programmierung ist die Rei-henfolge durch die Sequenz der Zeilen bestimmt.Wenn man ungünstig programmiert, dann werdenneu zu berechnete Werte benutzt, die noch nichtberechnet wurden und damit aus der vorigen Ab-tastzeit stammen. Die Folge sind nicht erwünschtefehlerhafte Totzeiten.

In einem Simulink-Modell wird die Abarbeitungs-reihenfolge aus dem Signalfluss bestimmt. Damitkönnen die oben genannten fehlerhaften Totzeitennicht entstehen. Gibt es einen Widerspruch - neu-er Wert wird schon eingeplant für seine eigene Be-

rechnung, dann ist dies eine arithmetische Schlei-fe. Simulink weist auf diesen Fehler hin, die Lösungist die Nutzung des Altwertes, typischerweise miteinem unified delay-block gespeichert.

Die Objektorientierung bricht en Datenfluss da-durch, dass die Objekte sich kennen und über diein Simulink in der Tinit dargestellten Aggregations-verbindung. Diese bestimmt aber nicht die Abar-beitungsreihenfolge in einer anderen Abstastzeit.

Zur Illustration soll folgendes Modell dienen. In die-sem Modell werden in C programmierte Datenspei-cher und Mittelwertbildner zusammengeschaltet.

Abbildung 3: Simulink Objectmodell WaveMng ohne Abarbeitungsreihenfolge

Das Bild zeigt das eigentliche Modell für den Da-tenfluss. Die FBs müssen in einer Abtastzeit pas-send nacheinander aufgerufen werden.

Für die Rechenzeiteffizienz ist eine Indexverwal-tung zentralisiert. Der FB WaveMngIx_FB (linksoben) incrementiert eigentlich nur einen Index fürdie WaveBuffer. Die Incrementierung wird in derstep-Abtastzeit vorgenommen, vermittelt über Pa-rameter. Der FB erscheint als Source-Block. DieFB WaveMngIx_FB berechnen mit der dynamischsich ändernden Mittelwertzeit Indizees und Fakto-ren für den Zugriff auf einen ’Altwert’. Das ist un-

abhängig von den Daten selbst. Wird beispiels-weise in einer Anwendung 9 Signale mit demgleichen Mittwelwert berechnet, beispielsweise 3-phasige Spannungen und Ströme, dann braucht esdiesen FB also nur einmal. Für eine andere Mit-telwertzeit gibt es den zweiten hier dargestelltenWaveMng_Ix_FB.

Die Daten werden nun in einem WaveData_FB ge-speichert, und zwar verwaltet von dem Index-Geber WaveMng_Ix_FB, aber unabhängig davon, obdavon welche Mittelwerte gebildet werden oder et-wa nur verzögert alte Daten abgegriffen werden.

Page 41: Simulink objektorientiert mit C-Kernfunktionen - Anleitung mit Demo- / Test-Version · 2019. 1. 2. · Simulink objektorientiert mit C-Kernfunktionen - Anleitung mit Demo- / Test-Version

7 ASPEKTE DER MODELL-GESTALTUNG 41

Letzlich gibt es die Mittelwertbildner AvgWave_FB,die die Werte aus den Datenbausteinen undder Indexberechnung nutzen und damit schnelleinen Mittelwert ermitteln können. Dazu folgen-

der Hinweis: Diese FBs verarbeiten korrekt nicht-ganzzahlige Avg-Schrittweiten und korrigieren denmöglichen numrischen Fehler der Mittelwert-Driftaufgrund floating-Rundungsprobleme.

Abbildung 4: Simulink Objectmodell WaveMng mit Abarbeitungsreihenfolge

In diesem Modell ist nun die Abarbeitungszeitmit Verbindungen gekennzeichnet. Die FBs habenEin- und Ausgänge, die zwar im Modell verdrahtetsind aber nicht auf der C-Ebene verwendet wer-den. Bei der Codegenerierung aus dem Modellwerden zwar diese Verküpfungen mit generiert. Sieentfallen aber letzlich beim Compilieren. Ein Com-piler optimiert in der Regel nicht genutzte Variablebzw. lässt sich entsprechend einstellen.

Mit der Abarbeitungsreihenfolge-Verdrahtungist nun gekennzeichnet, dass zuerst derWaveMngIx_FB (links oben) abgearbeitet werdenmuss, da sein Ausgang als Eingang bei denWaveMng_FB und WaveData_FB benutzt wird. Damitist gewährleistet, dass alle diese FB den gleichenIndex benutzten.

Für die Bildung der Mittelwerte (rechts unten) müs-sen sowohl die Daten gespeichert sein, als auchdie WaveMng_FB müssen gerechnet worden sein.Dann passen die Daten und Indizees für die Mitt-

welwertbildung zueinander, sind konsistent.

Die in C ungenutzten Ein- und Ausgänge werdendann generiert, wenn die

/**

* @simulink Object-FB, step-in, step-out.

*/ ....

Operation-Definition noch mit step-in und/oderstep-out gekennzeichnet ist. Der step-Eingangund -Ausgang wird dabei als letzter Ein-bzw. Ausgang angeführt. Ein Eingang istDYNAMICALLY_TYPED. Man kann also alle passen-den Signale anschließen. Ein Ausgang ist mituint32 typisiert und kann damit problemlos auchmit einem thiz-Ausgang der Hauptabtastzeit zu-sammengeschaltet werden, hier sichtbar mit einerAddition. Damit passt der Ausgang auch wiederan einen Eingang. Addierte Werte werden nichtbenutzt.

Page 42: Simulink objektorientiert mit C-Kernfunktionen - Anleitung mit Demo- / Test-Version · 2019. 1. 2. · Simulink objektorientiert mit C-Kernfunktionen - Anleitung mit Demo- / Test-Version

7 ASPEKTE DER MODELL-GESTALTUNG 42

7.2 Abarbeitungsreihenfolge bei der Initialisierung (Tinit)

Die Initialisierung wird in der mit Tinit defi-nierten Abtastzeit ausgeführt. Im generiertenCode auf dem Zielsystem ist das eine eige-ne step-Operation, die initial mehrfach durch-laufen wird, dann nicht wieder. Im Simulinkist die Initialisierung so nicht vorgesehen undwird daher als normale Abtastzeit ausgeführt.Allerdings sind die SFunctionen so gestal-tet dass die @simulink init-Routine mit TestisInitialized_ObjectJc(instance) ==0 vordem Aufruf ausgeführt wird. Ist die Initialisie-rung beendet, dann muss die Intialisierungsrou-tine intern setInitialized_ObjectJc(instance)

ausführen. Das ist gleichzeitig die Ansage,dass nun in den normalen Abarbeitungs-modus gegangen werden kann. Dort wirdisInitialized_ObjectJc(instance) getestet.

Für den generierten Code wird eine etwas an-dere aber gleichbedeutende Funktionalität ge-nutzt: Eine @simulink init-Routine muss einenreturnwert vom Typ bool zurückliefern, mit true

wenn die Initialisierung beendet ist. Liefert ei-ne init-Routinen false zurück, dann wird die In-tialisierung für alle Routinen zyklisch wiederholt,bis alle true zurückliefern. Der Returnwert soll

dem isInitialized_ObjectJc(instance) ent-sprechen. Für den generierten Code ist diese Vor-gehensweise einfacher, da damit auch Routinenintegriert werden können, die nicht auf ObjectJcbasieren. Diese werden in der Simulation weiterzyklisch gerufen, für das Zielsystem kann man sichdies sparen bzw. dort muss erkannt werden kön-nen, dass die Initialisierungsphase beendet ist.

Die @simulink init-Routinen müssen eigenstän-dig testen, ob die Initialisierung möglich ist. Dashängt an der Eingangsbelegung der zu aggregie-renden FBlocks:

• Die initiale Belegung aller statischen und al-lokierten Speicherzellen muss 0 sein. Die in-itiale Belegung von stacklokalen Variablenmuss auch null sein, wenn die Variablen nichtgarantiert funktional belegt werden. Die initia-lie Belegung von Outputs im Modell, die nochnicht berechnet wurden, ist 0.

• Folglich wird eine Input-Aggregation von ei-nem Ausgang, der noch nicht berechnet wur-de, mit null geliefert.

• Die

Page 43: Simulink objektorientiert mit C-Kernfunktionen - Anleitung mit Demo- / Test-Version · 2019. 1. 2. · Simulink objektorientiert mit C-Kernfunktionen - Anleitung mit Demo- / Test-Version

7 ASPEKTE DER MODELL-GESTALTUNG 43

7.3 Objektorientierte Simulink-Module, Verbindung über Handle

Das objektorientierte Prinzip soll nicht nur fürdie direkte Verbindung von C-Modulen verwendetwerden, sondern auch größere Simulink-Modul-Einheiten sollen in dieser Weise zusammenge-schaltet werden. Der Schlüssel für diese Herange-hensweise ist die Anordnung der relevanten Mo-duldaten in einem Object-FB. Dieser ist einerseitsso gestaltbar, dass er als Datenspeicher dienenkann: Die Ausgänge führen die Alt-Daten der letz-ten Abarbeitung, beim Aufruf werden die Neu-

Daten übernommen. Der Object-FB wirkt damit wieein Unit-Delay. Andererseits ist für den Datenaus-tausch in C eine Datenkonsistenz programmierbar.Zur Datenkonsistenz siehe TODO.

Dieser moduleigene Object-FB stellt die Modul-daten nach außen bereit. Im Modul können sichweitere modulinterne Daten befinden, die typi-scherweise mit Unit-Delay und anderen Simulink-Elementen gebildet werden.

7.4 Hinweise für Modellgestaltung

• Nutze package-paths: name-clash-Verhinderung.

• Gebe bei callback im Modell nur einen File an.

Page 44: Simulink objektorientiert mit C-Kernfunktionen - Anleitung mit Demo- / Test-Version · 2019. 1. 2. · Simulink objektorientiert mit C-Kernfunktionen - Anleitung mit Demo- / Test-Version

8 BASISFUNKTIONEN AUS DER EMC-LIBRARY 44

8 Basisfunktionen aus der emC-Library

Die emC Library steht im Begleitbeispiel im Un-terverzeichnis emC. Es handelt sich dabei um dasSubset, dass für allgemeine Anwender-Sfunctionsnotwendig ist.

Die emC-Library ist eine allgemeingültige Libra-ry [?]. Sie wurde ursprünglich als CRuntime-Javalike-Library in C mit der Entwicklung einesJava2C-Translators (Java to C) entwickelt und ent-hält diejenigen Routinen, die direkt in C bereitge-stellt werden. Die emC-Library hat sich im laufeder Zeit als hilfreich auch für die allgemeine C-Programmierung erwiesen. Bezüglich Java ist zu

bemerken, dass die ursprüngliche Intension derSprache, die wir heute als Java kennen, die Schaf-fung einer einheitlichen Programmierplattform fürembedded Systeme war. Das war in den Jahren1990 bis 95. Parallel zu dieser Entwicklung hat-te sich C in diesem Bereich etabliert, und als Ja-va fertig war, gab es das Internet. Dennoch ent-hält Java einige sehr günstige Ansätze für em-bedded Programmierung, die auch hier hilfreichsind. Dazu gehört die struct ObjectJc, die anjava.lang.Object als Konzept angelehnt ist. Eineallgemeine Beschreibung der emC-Library kann inwww.vishia.org/emc gefunden werden.

Das Subset der emC für allgemeine Anwender-S-Funtionen besteht aus folgenden wesentlichen Filesund Ordnern, die vollständige Funktionalität ist in den Files selbst dokumentiert:

• emc/source/OSAL: Enthält Headerfiles für die Definition einer Operation System Adaption Layer -Schicht. Insbesondere ist hier die os_sharedmem.h mit der os_AtomicAccess.h notwendig, da inden Sfunctions in Windows SharedMemory verwendet wird. Für die Implementierungsebene imZielsystem wird die OSAL-Schicht nicht vorausgesetzt.

• emc/sourceSpecials/os_Windows_64/ os_sharedmem.c Dies ist die Implementierung des SharedMemory Zugriffs für Windows.

• emc/source/emC enthält den Kern des emC, außerhalb eines Java-Konzepts. Hierbei wichtig ist:

• emc/source/emC/Handle_ptr64_emC Funktionen für das Abbild von Adressen im Speicher überHandle. Verwendet in der Sfunction-Ebene, nicht im Zielsystem.

• emC/source/emC/Object_emC.h Die Basisstruktur ObjectJc. Sie wird auch im Zielsystem verwen-det, da in den Anwender- struct - Definitionen enthalten. Sie kann im Zielsystem hilfreich seinwenn dort Reflection eingesetzt werden, ansonsten nicht.

• emC/source/Fwc/fw_ExcStacktrcNo.h: Es ist möglich, mit einer in der emC definierten Schreib-weise für Exceptionhandling zu arbeiten. Diese wird in den internen emC-Quellen verwendet undkann auch dem Anwender empfohlen werden. Dieses Headerfile definiert die Makros so, dasskein Exceptionhandling verwendet wird. Das ist die Voreinstellung für einfache und allgemeingülti-ge Anwender-Sfunctions.

• emC/source/Jc/ReflectionJc.h Der Zugriff auf die Daten über Reflection is für die Sfunctions aufSimulinkebene integraler Bestandteil. Im Zielsystem können Reflection verwendet werden, müs-sen aber nicht. Es ist auch möglich, einen sogenannten Target - Proxy zu erstellen, der die Re-flectioninformationen auf direkte Speicherzugriffe umsetzt und so das Zielsystem von zusätzlichemAufwand entlastet. Siehe dazu http://www.vishia.org/Inspc/html/proxytarget_de.html.

• emC/incApplSpecific/stdef_SmlkSfunc/applstdefJc.h Das Headerfile applstdefJc.h wird inden Sources der emC includiert und soll im Raum der Applikation definiert werden. Es wird überden Include-Path gefunden. Dieses Verzeichnis enthält die Ausführung für Sfunctions unter MS-Windows mit einem Visual-Studio-Compiler.

• emC/incApplSpecific/TagetNumericSimple Dieses Verzeichnis im Includepath des Target ent-hält eine Version von applstdefJc.h, in der alle textuellen und Reflection - Bezüge nicht enthalten

Page 45: Simulink objektorientiert mit C-Kernfunktionen - Anleitung mit Demo- / Test-Version · 2019. 1. 2. · Simulink objektorientiert mit C-Kernfunktionen - Anleitung mit Demo- / Test-Version

8 BASISFUNKTIONEN AUS DER EMC-LIBRARY 45

sind. Es ist insbesondere für ein Target mit nur numerischen Aufgaben (DSP) gedacht. Speicher-allokierung in der startup-Phase ist vorgesehen.

• emC/incApplSpecific/TargetReflAllocOnStatup Dieses Verzeichnis im Includepath des Targetenthält eine Version von applstdefJc.h, die mit Speicherallokierung in der Startup-Phase arbeitet,ansonsten aber das Reflection - Handling unterstützt. Es ist damit für Applikationen geeignet, dieetwa auf einem ARM-Prozessor als Zielsystem arbeiten.

• emC/sourceSpecials/FwConv_h/fw_StringJcSimple.h Dieses Headerfile wird in applstdefJc.h

includiert, wenn keine String-Verarbeitung und keine Reflection-Unterstützung im Zielsystem ver-wendet werden soll.

• D:/vishia/Smlk/Example_ObjO/emC/sourceSpecials/cc_SmlkSfunc Dieses Verzeichnis ist für dieGenerierung der Sfunction in den Includepath mit aufzunehmen. Es enthält insbesondere eincompl_adaption.h für die Definition compilerspezifischer Makros für den MS-Visual-Studio-Compilerim Zusammenhang mit der emC.

• D:/vishia/Smlk/Example_ObjO/emC/sourceSpecials/cc_Msc6 Dieses Verzeichnis ist für die Ge-nerierung eines Zielsystems auf dem PC aufzunehmen, wenn ein MS-Visual-Studio-Compiler für32 bit Systeme verwendet wird. Dies wird empfohlen um das Verhalten des generierten Codes ineiner 32-Bit-Umgebung auf dem PC zu testen. Es enthält das dazu passende compl_adaption.h.

Page 46: Simulink objektorientiert mit C-Kernfunktionen - Anleitung mit Demo- / Test-Version · 2019. 1. 2. · Simulink objektorientiert mit C-Kernfunktionen - Anleitung mit Demo- / Test-Version

9 GENERIERUNG DER SFUNCTIONS 46

9 Generierung der Sfunctions

Die Generierung der Sfunction-Wrapper, tlc-Filesund Bus-Scripts aus den Headerfiles wird mit ei-nem m-File im Matlab aufgerufen. Dabei werdendie erforderlichen Sekundär-Source-Files aus denInformationen in den Headerfiles generiert. Da-nach wird der mex-Compiler für die Sfunctions auf-gerufen.

Nach der Vorlage werden folgende File-Typen inden folgenden Verzeichnissen generiert. Die Ver-zeichnisse sind dabei im Aufrufscript festgelegt,können also beliebig angepasst werden. FolgendeVerzeichnisaufteilung ist daher ’nur’ als bewährterVorschlag zu sehen.

• simulink/MODELDIR/+genSfn/pathto/OPERATION_SfH.c: Sfunction-wrapper C-File und tlc-Files proSfunction-Block (pro Object-FB und Operation-FB im Headerfile)

• simulink/MODELDIR/+genSfn/mex_NAME.m: Matlab-Script zum Aufruf des mex-Compilers, jeweilsfür ein zmake-Aufruf bzw. pro Anwender-Generierscript. Mit einem Aufruf können mehrere Header-files bearbeitet werden. Wenn das Generierscript genau einen zmake-Aufruf enthält, dann sollteder NAME dem Namen des Generierscripts und damit dem Namen des zugehörigen Modells oderder Library entsprechen.

• mex/* Dieses Verzeichnis enthält die generierten mex64-DLL. Es wird empfohlen, dieses Ver-zeichnis parallel zu den Simulink-Quellen abzulegen und nicht in eine Versionsverwaltung aufzu-nehmen. Es sind ausschließlich generierte Files. Die Herauslösung aus den Simulink-Quellen istgünstig, damit etwa in einem Versionsmanagement-System die Quellen von Generaten getrennterscheinen, oder bei Weitergabe von Informationen Quellen und Generate getrennt sind. Die ge-nerierten mex-Files sind relativ viele große Files (für dieses Beispiel bereits 16 MByte), so dasseine getrennte Handhabung sinnvoll ist. Man kann das mex-File als ein zip-File beispielsweise ineinem Versionsmanagement speichern, um die Generate sofort ohne Neugenerierung verfügbarzu haben oder um einen älteren Stand sofort laufen lassen zu können.

• mex/OPERATION_mex.mex64: Sfunction-Library wird direkt von Simulink geladen und benutzt beiSimulationslauf (Ergebnis der mex-Compilierung)

• mex/OPERATION_mex.mex64.pdb: Zugehörige Programm Data Base - Outputfile der Compilierungvon Microsoft Visual Studio zur Debugunterstützung: Die Ausführung von Sfunctions kann mitVisual Studio Einzelschritt-Debugged werden.

• mex/tlc_c/OPERATION_SfH.tlc: tlc-File, Steuerfile für Target Language Compiler und Accelerator-Mode für Simulink. Die tlc-Files werden hier für die Codegenerierung erwartet. Sie werden beimmex-Aufruf aus dem .../+src2Sfn-Verzeichnis kopiert.

• gensrc_Refl/HEADER.crefl: Reflection C-File. Pro Headerfile wird ein Reflection-File erzeugt.Dieses wird in den Quellfiles includiert. (#include "gensrc_Refl/...crefl"). Die Reflection-Fileskönnen auch im Anwendersystem (Target) einbezogen werden, wenn dort die gleiche Inspector-Unterstützung vorgesehen ist. Dies wird empfohlen. Damit kann ein einheitliches System der Da-tenzugriffe sowohl im Simulationslauf als auch im Anwendersystem genutzt werden. Soll im Ziel-system keine Reflections verwendet werden, dann kann das include bedingt formuliert werden.

• simulink/MODELDIR/+genBus/MODEL_genBus.m Matlab-Script zum Generieren der Bus-Objects imMatlab-Workspace. Dieses File ist dem Simulink-Modell bzw. der Library zugeordnet. Die Einord-nung erfolgt deshalb innerhalb der Modell-Quellen, weil dieses Script immer beim Start des Mo-dells aufgerufen und aufgefunden werden muss. Das Matlab-Script für die Busgenerierung solltedaher auch als Callback im Modell eingetragen sein.

Page 47: Simulink objektorientiert mit C-Kernfunktionen - Anleitung mit Demo- / Test-Version · 2019. 1. 2. · Simulink objektorientiert mit C-Kernfunktionen - Anleitung mit Demo- / Test-Version

9 GENERIERUNG DER SFUNCTIONS 47

9.1 Generierscript als Matlab-Script

Es wird empfohlen, pro Modell und pro Library ein Generierscript anzulegen, dessen Filename demNamen des Modells oder der Library entspricht. Das Matlab-Script enthält am Anfang Matlab-Befehle,danach folgt für Matlab als Kommentar gesetzt das JZtxtcmd-Steuerscript für die Generierungssteue-rung. Als Vorlage dient das Matlab-Script, für die Generierung der Sfunctions des Orthogonaloszillator.Das Script wird folgend in Teilen als Kasten dargestellt und die Teile darunter beschrieben. Das gesamteScript ist auf der beiliegenden Beispielsoftware untersimulink/lib/+mkSfn/lib_OrthOsc_genBusSfunc.m zu finden.

function lib_OrthOsc_genBusSfunc()

rootPath = evalin('base', 'rootPath');

clc;

clear mex;

currdir_ = pwd;

cd(rootPath);

display('Generate S-Fuctions for lib_OrthOsc ...');

system('java.exe -cp zbnfjax/zbnf.jar org.vishia.jztxtcmd.JZtxtcmd

simulink/lib/+mkSfn/lib_OrthOsc_genSfn.m');

genBus.lib_OrthOsc_genBus(); %just generated script

genSfn.lib_OrthOsc_mex(); %just generated script.

display('successfull')

cd(currdir_);

end

Das ist der für Matlab wirksame Teil. Das Script berücksichtigt, dass ein anderes Verzeichnis aktuelleeingestellt ist als ein benanntes rootPath-Verzeichnis. Für das Script ist der rootPath relevant.

Die Generierung wird als Cmd-Zeile als Java-Aufruf ausgeführt, wobei das eigene File als Argument alsJZtxtcmd-Script angegeben ist.

Die mit dem Script passend generierten m-Files werden danach aufgerufen: Busgenerierung und mex-Compilierung.

%{

==JZtxtcmd==

currdir = <:><&scriptdir>/../../..<.>;

include ../../../SmlkSfuncJZtc/simulinkSfuncBusGen.jzTc;

Mit dem %{ ist der Rest für Matlab Comment. Das JZtxtcmd-Script beginnt an dem folgenden Label. Dasist eine Eigenschaft jedes JZtxtcmd-Scripts.

Das Script soll immer ein currdir festlegen. <&scriptdir> ist das absolute Verzeichnis in dem dasScript steht. Das currdir zeigt hier auf das Basisverzeichnis der Simulink-Applikation (Basis des Ar-beitsbereiches im Filesystem). Darauf beziehen sich dann die relativen Fileangaben.

Das Anwenderscript muss das eigentliche Generierscript includieren. Dieses ist anwendungsunabhän-gig, kann aber Anpassungen enthalten. Vor dem Start der JZtxtcmd-Abarbeitung werden alle includier-ten Scripts als Einheit in eine interne Abbildung übersetzt.

Fileset srcHeader =

( srcc_FB:AngleBlocks_FB.h

, srcc_FB:OrthOsc_FB.h

);

Page 48: Simulink objektorientiert mit C-Kernfunktionen - Anleitung mit Demo- / Test-Version · 2019. 1. 2. · Simulink objektorientiert mit C-Kernfunktionen - Anleitung mit Demo- / Test-Version

9 GENERIERUNG DER SFUNCTIONS 48

Fileset includepath =

( srcc_FB

, emC/source

, emC/source/OSAL

, emC/incApplSpecific/stdef_SmlkSfunc

, emC/incComplSpecific/cc_SmlkSfunc

, src2_refl

);

Im Script wird das Fileset für die Input-Files src definiert. Der : als Verzeichnistrenner statt / spalteteinen Localpath-Anteil ab, der hier aber nur aus dem Filenamen besteht. Es ist möglich, Files mit einemVerzeichnis im Include der Anwenderquellen zu erzeugen.

Das Fileset für den includepath ist für die Compilierung wichtig. Die hier stehenden relativen Pfadezählen auch für die Generierung ab dem currdir, der Basis des Arbeitsverzeichnisses. Es ist hier auchmöglich, absolute Verzeichnisse anzugeben.

Fileset lib_Sfn =

( mex/emC_SmlkSfn

);

Fileset lib_Accel =

( mex/emC_SmlkAccel

);

Fileset lib_RAccel =

( mex/emC_SmlkRAccel

);

Diese Filesets benennen Libraries, die jeweils für Sfunctions, Accelerator-Mode und Rapid-Acceleratorgrundsätzlich benutzt werden sollen.

## All sources for compilation to the named header file, for target and raccel.

Fileset srcTlc_OrthOsc_FB =

( srcc_FB/OrthOsc_FB.c ##same c-file as header

, srcc_FB/AngleBlocks_FB.c ##same c-file as header

);

Diese Sources werden in das tlc-File notiert. Sie werden damit sowohl beim Rapid Accelerator als auchfür das Zielsystem compiliert. In diesem Fall ist es der aufgerufene Code der Sfunction. Da diese Sourcesehr wahrscheinlich bei Neugenerierung der Sfunction auch geändert sein könnte, wird die Quelle direktund nicht über eine Library eingebunden.

## All sources for compilation to the named header for SFnc additional to the srcTlc

Fileset src_OrthOsc_FB =

( &srcTlc_OrthOsc_FB ##Use the sources which are named for tlc

, emC/source/Fwc/fw_ReflectionBaseTypes.c

, emC/source/Fwc/fw_Object.c

, emC/source/Fwc/fw_handle_ptr64.c

Page 49: Simulink objektorientiert mit C-Kernfunktionen - Anleitung mit Demo- / Test-Version · 2019. 1. 2. · Simulink objektorientiert mit C-Kernfunktionen - Anleitung mit Demo- / Test-Version

9 GENERIERUNG DER SFUNCTIONS 49

, emC/sourceSpecials/FwConv_c/fw_ExcStacktrcNo.c

, emC/sourceSpecials/os_Windows_64/os_sharedmem.c

);

Diese Filesets benennen die Quellfiles, die jeweils für einen Headerfile als Input (Fileset srcHeader)benutzt werden sollen, zusätzlich zum generierten Wrapper der Sfunctions. Wenn die compilierten Ob-jects sich in den Libraries befinden, können diese Filesets klein gehalten werden. In diesem Fall sinddie Files vollständig, es wird nichts aus der Library beim Linken zusätzlich benötigt.

Es wird davon ausgegangen, dass alle in einem Headerfile beschriebenen Sfunctions die gleichen Zu-satzfiles benötigen. Dabei ist ein unnötiger Zusatzfile im konkreten Fall kein Fehler und kaum Aufwand,lediglich der mex64-Sfunction-dll-File wird etwas größer. Wenn hier Files fehlen und diese auch nicht inden Libraries gefunden werden, gibt es beim mex-Compilieren Linker-Fehler.

Subtextvar genAllocmem(String dst, String nameStruct, Num ident) =

<:>(<&nameStruct>*) malloc(sizeof(<&nameStruct>)) /*JZtc: user-specific */ <.>;

Dieses Codefragment wird in den tlc-File eingebracht und beschreibt, wie im Zielsystem eine Speicher-allokierung auszusehen hat. In einer Sfunction wird dies nicht benutzt, dort wird, da auf dem PC ab-laufend, immer malloc verwendet. Im Zielsystem kann es sein, dass mit statischem Speicher gearbeitetwerden soll.

zmake "simulink/lib:lib_OrthOsc" := simulinkSfuncBusGen(.:&srcHeader

, fileBus = ":+src2Bus/*_genBus.m"

, dirMex = "mex"

, coptions = "-TP -EHa"

, dirMexcc=":+src2Sfn"

, dirSfunc = ":+src2Sfn/OrthOsc", dirTlc = ":+src2Sfn/OrthOsc"

, dirRefl = "src2_refl"

##, html=":+src2Sfn/OrthOsc/test.html"

);

Die main-Routine enthält nun das zmake-Statement zur Generierung der Ergebnisfiles. Die allgemeineForm eines zmake-Statement in einem JZtxtcmd-Script nennt links das zu erzeugende File (Destination)und rechts vom := die Bedingung der Erzeugung. Da hier mehrere Files erzeugt werden, sind derenVerzeichnis oder Namen als Argumente angegeben. Beim zu erzeugenden File (links) ist pragmatischVerzeichnis und Name des zugehörigen Modells angegeben. Diese Angaben, getrennt mit ’:’ werdendann zur Namensbildung der Zielfiles verwendet. Folgende Angaben für Destinations gelten:

• Die destination des zmake links vom := gibt vor dem : das Verzeichnis an, das als Basisverzeichnisbenutzt wird, wenn die Angaben der folgenden Verzeichnisse mit : beginnen. Das ist eine spezielleEigenschaft dieses Generierscripts, keine allgemeine des zmake.

• Die destination des zmake links vom := gibt nach dem : einen File-Namen an, der als Filenameverwendet wird, wenn von diesem Script genau 1 file erzeugt wird. Der Name sollte dem Namendes Modells oder der Library folgen, die die hier zu generierende Sfunction ursächlich enthält.

• fileBus: Pfad des zu erzeugenden Bus-Generierfiles. Es wird ein File für alle Busse (aus al-le struct-Definitionen) erzeugt, die die Annotation @simulink bus tragen. Wenn der Pfad mit ’:’beginnt, dann wird der Pfad der Destination-Angabe als Basis verwendet. Das ist auch bei denanderen Pfaden möglich. Das ’*’ wird durch den Namen der Destination-Angabe ersetzt. Damitfolgt der Pfad des Bus-Generierfiles dem Pfad der Library aus der Destination-Angabe.

Page 50: Simulink objektorientiert mit C-Kernfunktionen - Anleitung mit Demo- / Test-Version · 2019. 1. 2. · Simulink objektorientiert mit C-Kernfunktionen - Anleitung mit Demo- / Test-Version

9 GENERIERUNG DER SFUNCTIONS 50

• dirMex Verzeichnispfad, in dem die generierten mex-Files abgelegt werden. Wird diese Angabeweggelassen dann erfolgt keine mex-Compilierung. Der Name des zu erzeugenden mex-Files indiesem Verzeichnis folgt dem Namen der Destination-Angabe.

• coptions Diese Optionen werden beim mex-Aufruf als COMPFLAGS='$COMPFLAGS .....' überge-ben. Sie werden vom mex-Compiler dem Zielsystemcompiler durchgereicht. In diesem Fall wirdmit /TP eine C++-Compilierung der .c-Quellen ausgeführt. Mit /EHa wird eine Exception auchdann mit catch abgefangen, wenn sie nicht mit throw erzeugt wurde sondern beispielsweise undinsbesondere durch eine Memory-Access-Exception hervorgerufen wurde. Das lässt sich auch inder XML-Configurationsfile zum mex-Compiler eintragen, siehe 11.5, S. 61

• dirMexcc Verzeichnispfad, in dem das Matlab-Script zur Gegerierung der mex-Files abgelegtwird. Der Name des Scripts folgt der Angabe des destination-files des zmake-Aufrufes, also hierlib_OrthOsc.

• dirSfunc Verzeichnispfad, in dem die Wrapper.c der Sfunctions abgelegt werden und in dem dasmex-Generierfile abgelegt wird. Wird diese Angabe weggelassen dann werden keine Sfunctionserzeugt. Damit ist es möglich mit diesem Script nur Bus-Matlab-Script-Files zu erzeugen. DerName des zu erzeugenden mex-Files in diesem Verzeichnis folgt dem Namen der C-Funktion, dieals Object-FB oder Operation-FB bezeichnet ist.

• dirTlc: Pfad in dem die tlc-Files abgelegt werden.

• dirRefl: Pfad in dem die Reflection-Files abgelegt werden. Pro Headerfile wird ein Reflectionfileerzeugt. Dessen Name wird aus dem Namen des Headers gebildet und ist damit eindeutig. Wirddiese Angabe weggelassen oder mit null besetzt, dann erfolgt keine Reflectionfilegenerierung.Die Reflectionfiles können passend zum Header auch anderweitig generiert werden.

• html Pfad eines html-Files, der das Parserergebnis des jeweiligen Headerfiles in html-Form ent-hält. Dieses File ist nur notwendig, wenn die Generierscripts angepasst werden. Es ist dort ersicht-lich, wie das Parserergebnis (als Java-intern-Daten) abgelegt wird. Im Muster ist dieses Argumentkommentiert.

Die Schreibweise eine Zeile pro Argument(-Gruppe) mit Komma vorn ist empfohlen. Dann kann mitKommentarzeichen ## mit dem Rest der Zeile das Argument bei Bedarf wegkommentiert werden bzw.einfach wieder hinzugenommen werden, gezeigt mit dem , html = ....

zmake ist ein spezifischer Aufruf im JZtxtcmd ähnlich wie call. Die simulinkSfuncBusGen-Subroutine istdie zmake-Routine. Das erste Argument ist ein Fileset. Hinweis: Das zmake führt keine automatischenPrüfungen auf Datum und bedingte Übersetzung aus. Dies ist bei Bedarf, nicht in diesem Fall, im derjeweiligen zmake-Subroutine spezifisch zu programmieren.

Die Verzeichnisse werden angelegt, wenn sie nicht vorhanden sind. Vorhandene Files in den Verzeich-nissen werden nicht gelöscht. Das ist ebenfalls spezifisch in dieser Weise in den Subroutinen so pro-grammiert und kann auch geändert werden.

Page 51: Simulink objektorientiert mit C-Kernfunktionen - Anleitung mit Demo- / Test-Version · 2019. 1. 2. · Simulink objektorientiert mit C-Kernfunktionen - Anleitung mit Demo- / Test-Version

9 GENERIERUNG DER SFUNCTIONS 51

9.2 Compilierung der C-Quellen mit C++-Compiler

Es ist zweckmäßig, einen C++-Compiler zu ver-wenden statt dem C-Compiler, auch wenn nur C-Code compiliert wird. Defakto gibt es einen Quasi-C-Standard, der an Sprachfeatures von C++ par-tizipiert, einen C++-Compiler erfordert, ohne aberC++ selbst zu sein. Auch für die meisten Zielsyste-me stehen C++-Compiler zur Verfügung. Die ver-besserten Sprachfeautes sind im wesentlichen:

• Bessere Warnings bei Programmierfehlerninsbesondere bei Pointer-Casting.

• Möglichkeit, Variable-Definitionen im Ablauf-code unterzubringen, nicht nur am Anfang.

• inline-Funktionen

• Ein verbessertes Exception-Handling, ins-besondere mit der Möglichkeit, Speicherzu-griffsfehler als Exception abzufangen. Letze-res hilft bei den Sfunctions, da dann nicht dasSimulink abstürzt sondern eine klare Fehler-meldung generiert wird.

Die Generierung der Sfunction-Wrapper kann ins-besondere das Exception-Handling nutzen, wennbei erwartbaren Fehlern nicht der gesamte Matlab-Prozess beendet werden soll.

Man kann die C++-Compilation nur für die Sfunc-tion vorschreiben, indem die coptions="-TP " an-gegeben wird, siehe voriges Kapitel.

Für die (Rapid-) Accelerator-Compilierung gilt je-doch, dass der generierte Modell-Code als C zucompilieren ist. Das hängt von zugebundene Li-braries für die Kommunikation mit Simulink ab.Ein C++-Compiler erzeugt andere Linker-Labels. InC++ kann man mit extern "C" zwar auch mit C-Libraries mischen, das ist hier aber in der Codege-nerierung so nicht vorgesehen.

Man kann folglich im XML-File, der in 11.5, S. 61beschrieben ist, nicht generell das -TP-Flag für dieC++-Compilierung setzen.

Die konkreten Aussagen gelten für den Microsoft-Compiler. Andere Compiler haben andere spezifi-sche Optionen.

Page 52: Simulink objektorientiert mit C-Kernfunktionen - Anleitung mit Demo- / Test-Version · 2019. 1. 2. · Simulink objektorientiert mit C-Kernfunktionen - Anleitung mit Demo- / Test-Version

10 INTERNAS DER SFUNCTION 52

10 Internas der Sfunction

10.1 Port based oder FB-Abtastzeiten

Ein Object-FB hat grundsätzlich zwei Abtast-zeiten: Tinit und eine entweder über die Input-Port-Verbindungen oder per Parameter determi-nierte Operation-Abtastzeit. Die Tinit-Zeit dienteigentlich nur zur Zuordnung dieser Teile in derZielsystem-Codegenerierung. Dort werden alleTinit-Operationen in einer eigenen step-Funktionzusammengefasst (im tlc OutputsForTID), diedann im Zielsystem am Anfang vor Beginn der Ab-arbeitung der anderen Zeitscheiben gerufen wird.Für die Simulink-Ebene ist das so nicht organi-sierbar, da im Simulink ein eigener Initialisierungs-Ablauf mit Datenverbindungen der FBs nicht vorge-sehen ist. Die Zuordnung bestimmter Ports zu Tinitist auf der Simulink-Ebene nur formalistisch, letz-lich als Farbgebung bei der Anzeige der Abtastzeitim Diagramm. Da Verbindungen in Tinit nur für dieHandle der Object-FB ausgeführt werden und al-so keine Operationen im Modell beinhalten, ist dieBelegung der Verbindung am Output-Port in derHauptabtastzeit ebenfalls erfolgreich.

Die Zeit Tinit kann man folglich auch mit einer lan-gen Periode belegen, da sie in Simulink nicht ver-wendet wird und in der Zielsystemgenerierung ei-nem eigenen Zeitregime unterliegt.

Wie ist statt dessen die Initialisierung gere-gelt? In der Basis-struct ObjectJcin den Datendes Object-FB gibt es ein Bit isInitialized. Inder Opeartion-Abtastzeit wird jeweils geprüft oballe für Tinit notwendigen Inputwerte der Hand-le anstehen. Ist dies der Fall dann wird die init_-Routine gerufen. In der init_-Routine kann indivi-duell geprüft werden, ob die Input-FB in ihren Da-ten bereits isInitialized ==1 ansagen, also ih-re Initialisierung abgeschlossen haben. Abhängigdavon wird schlussendlich isInitialized = 1 ge-setzt. Die init_-Routine kann also mehrfach auf-gerufen, wenn vorgelagerte Object-FB noch nichtals initialisiert angesehen werden. Das ist notwen-dig bei zyklischen (gegenseitigen) Referenzie-rungen von Object-FBs. In der init-Routine kön-nen Werte berechnet werden, die der nachfolgen-de Object-FB dann benutzt. Bei zyklischen Refe-renzierungen muss auf Anwenderprogrammiere-bene geklärt sein, dass die Object-FB nicht ge-genseitig auf isInitialized ==1 warten. Ëinermuss den Anfang machen". Um einen solchen

Fehler zu detektieren, wird mit einem Durchlauf-zähler die Anzahl der init-Zyklen auf 100 begrenztund danach wird eine Fehlermeldung abgesetzt.Man kann damit 99 FB in der Abtastreihenfolgefalsch herum verdrahten (der letzte in der Reihemeldet isInitialized =1). Bei etwas komplexe-ren Initialisierungs-Abhängigkeiten kann es in derPraxis zu 2..3 Durchläufen kommen.

In den nachfolgenden Abtastschritten wird dannwegen isInitialized ==1 die step-Funktiondes Object-FB gerufen.

Ein Object-FB präsentiert seinen eigenen Handlean Outport Port 0 und 1, Port 0 für Tinit und Port1 für Tstep. Beide Werte sind identisch. Der Out-put Port 0 wird beim ersten init_-Aufruf belegt, un-abhängig von isInitialized =1. Der Output Port1 ist 0, solange die Initialisierung noch nicht aus-geführt wurde.

Ein Operation-FB hat grundsätzlich nur ei-ne Abtastzeit. Diese ist INHERITED. Wenn Ein-gangwerte verarbeitet werden, dann bestimmendiese die Abtastzeit. Der this-Input-Port 0 desOperation-FB muss vom Output Port 1 des Object-FB versorgt werden, damit die Abarbeitungsrei-henfolge in der selben Abtastzeit geregelt ist:Der Object-FB wird zuerst verarbeitet. Wennder Operation-FB eine abweichenden Abtast-zeit hat, dann sollte der Output-Port 0 (Tinit)benutzt werden, mit einer Rate-Transition. Dasist konsequent im Design. Dann ist keine Rei-henfolge zwischen der Object-FB-Operation unddem Operation-FB geregelt. Nur die InitialisierungisInitialized ==1 wird festgestellt. Das ist häu-fig passend, wenn beispielsweise in einer lang-samen Abtastzeit Einstellungen verändert werden.Die Datenkonsistenz ist gewährleistet, wenn ent-weder auch insbesondere im Zielsystem unter-setzte Abtastzeiten verwendet werden oder eineKonsistenz-Sicherung mittels Mutex-Mechanismenauf C-Ebene erfolgt.

Werden von einem Operation-FB keine weite-ren Eingangswerte verarbeitet sondern nur in-terne Werte des zugehörigen Object-FB, dannist der this-Input-Port 0 mit dem Output-Port 1des Object-FB zu verbinden. Dieser determiniertdann mit seiner Arbeits-Abtastzeit die Abtastzeit

Page 53: Simulink objektorientiert mit C-Kernfunktionen - Anleitung mit Demo- / Test-Version · 2019. 1. 2. · Simulink objektorientiert mit C-Kernfunktionen - Anleitung mit Demo- / Test-Version

10 INTERNAS DER SFUNCTION 53

des Operation-FB und sichert die korrekte Abar- beitungsfolge.

10.2 Abarbeitung des Modells im Normalmode und Debuggen im C-Code

Einige C-Funktionen der Wrapper der Sfunctions werden bereits bei Simulation - Update Diagram auf-gerufen. Diese Informationen werden im Diagramm zum Check benötigt und gegebenenfalls angezeigt(Disply - Signals & Ports - ...) Hinweis: In diesen C-Funktionen können keine Daten in DWork-Vektorengesetzt werden.

• mdlInitializeSizes(): In dieser C-Funktion werden die Anzahl und Typen der Ports festgelegt.

• mdlSetInputPortSampleTime() und mdlSetOutputPortSampleTime(): Diese C-Funktionen wer-den generiert und gerufen, wenn keine feste Abtastzeit über ein Argument Tstep im ctor als Para-meter übergeben wird, für alle Ports, deren Abtastzeit aus dem Modell ermittelt werden kann.

• mdlInitializeSampleTimes()

• mdlSetInputPortDimensionInfo() und mdlSetOutputPortDimensionInfo(): Diese C-Funktionenwerden generiert und gerufen, wenn die Anzahl der Arrayelemente nicht feststeht (DYNAMICAL-LY_SIZED)

• mdlSetInputPortDataType() und mdlSetOutputPortDataType(): Diese C-Funktionen werden ge-neriert und gerufen, wenn Ports mit void bzw. DYNAMICALLY_TYPED typisiert sind. Es wird der imModell festgestellte Typ übergeben. Adäquates gilt für

• mdlSetDefaultPortDataTypes(): Aufgerufen nachdem alle In- und Output Port Typen gesetzt wor-den sind. Man kann hier umdefinieren und muss insbesondere alle nicht angeschlossenen Portsebenfalls typisieren.

Siehe dazu auch (TODO es gab hierzu eine Simulink-Übersichtsdoku über Simulation von Mathworks)

Im Normalmode wird das Modell aufgrund der intern gespeicherten und aufbereiteten Modelldaten inter-pretativ abgearbeitet. Die Sfunctions werden nach Datenaufbereitung gerufen. Diese Funktionen kön-nen nun die vorbereiteten DWork-Vektoren nutzen.

• mdlStart(): Diese Routine allokiert den Speicher für die internen Daten eines Object-FB.

• mdlInitializeConditions(): In dieser Routine wird der ctor eines Object-FB gerufen. Die Non-tunable Parameter sind hier präsent.

• mdlOutputs(): Diese Routine wird dann zyklisch als Simulation gerufen. Es wird auch mdlUpdate()

gerufen wenn vorhanden. Die mdlOutputs() bekommt eine tid (Task Id) mitgeteilt, wenn es ver-schiedene Abtastzeiten gibt. Insbesondere ein Object-FB kennt neben der step-Abtastzeit dieTinit. Diese wird ignoriert. Statt dessen wird die Initialisierungsroutine zyklisch anfänglich durch-laufen, bis sie erfolgreich war. Es wird dabei isInitialized_ObjectJc() getestet. Das zugehörigeFlag muss in der Initialisierungsroutine gesetzt werden - oder im ctor, wenn es keine Initialisie-rungsroutine gibt.

Page 54: Simulink objektorientiert mit C-Kernfunktionen - Anleitung mit Demo- / Test-Version · 2019. 1. 2. · Simulink objektorientiert mit C-Kernfunktionen - Anleitung mit Demo- / Test-Version

10 INTERNAS DER SFUNCTION 54

Man kann mit einer Microsoft Visual Studio Entwicklungsumgebung (IDE) in diese C-Funktionen hinein-debuggen. Das erfolgt in dem die IDE an den Matlab-Prozess im MS-Windows angehangen wird:

Abbildung 5: Debuggen in Sfunction - Attach to process

Das Anhängen sollte erfolgen, bevor das betref-fende Modell geöffnet wird. Mit Start des Simu-lation - Update Diagram werden nun die entspre-chenden Softwaremodule my_Sfunction.mex64 imMatlab geladen. Dieses bekommt das angehäng-te Visual Studio mit. Wenn die Sfunction mit De-buginformationen übersetzt wurden - Option -g

- dann existiert neben dem my_Sfunction.mex64

die zugehörige pdb-Datei mit den Debuginforma-tionen. In der my_Sfunction.mex64.pdb steht alsAbsolutpfad der Verweis auf die zugehörige Quell-

files. Wenn also die Sfunction auf dem gleichenRechner - oder mit der gleichen Anordnung aufder Festplatte - übersetzt worden ist, kann Vi-sual Studio nunmehr einen Haltepunkt in einempassenden Quellfile der richtigen Maschinencode-Speicheradresse zuordnen und beim Durchlaufenin den Debug-Einzelschritt gehen. In dieser Zeit istSimulink nicht mehr bedienbar, da der Thread imDebug steht. Setzt man passend Haltepunkte undlässt nach Einzelschritt den Prozess jeweils weiter-laufen, dann ist ein günstiges Debuggen möglich.

Page 55: Simulink objektorientiert mit C-Kernfunktionen - Anleitung mit Demo- / Test-Version · 2019. 1. 2. · Simulink objektorientiert mit C-Kernfunktionen - Anleitung mit Demo- / Test-Version

11 ACCELERATOR- UND RAPID ACCELERATOR MODE 55

11 Accelerator- und Rapid Accelerator mode

Im Normalmode wird das Modell interpretativ ab-gearbeitet. Die Sfunctions werden jeweils nachVorbereitung in der mex64-dll gerufen.

Im Accelerator-Mode wird das gesamte Modellals große mex64 - dll übersetzt. Dazu wird aus demModell eine Codegenerierung gerufen, die im Un-terschied zur Zielsystem-Codegenerierung direkteAufrufe der Verbindung zum Simulink enthält. DerCode ist grundsätzlich lesbar, hilfreich bei Compi-lerfehlern, aber spezifisch für die Verwendung imAccelerator aufbereitet.

Abhängig von der OptionSS_OPTION_USE_TLC_WITH_ACCELERATOR wird nunder Code der Sfunction so wie für das Zielsystemüber den tlc-File in den gesamten Modellcode ein-gebunden - oder die Sfunction wird wie beim Nor-malmode aufgerufen. Letzteres braucht dann et-was mehr Rechenzeit. Es gibt Sfunction, die nichtfür das Zielsystem vorgesehen sind und die Son-derbedingungen des Starts und des Terminate be-nötigen. Die Sfunction step_Service_Inspc_SfH

ist ein Beispiel dafür. Diese legt einen extraThread für die Socketkommunikation an undöffnet einen Socket. Für diese Sfunction darfSS_OPTION_USE_TLC_WITH_ACCELERATOR nicht ge-setzt sein. Das wird gesteuert mit der Annotation

@simulink Object-FB, , accel-tlc.

Nur mit dieser vorhandenen Option wirdSS_OPTION_USE_TLC_WITH_ACCELERATOR gesetzt.

Im Rapid-Accelerator-Mode wird mit dem Startder Simulation vom Modell intern C-Code gene-riert. Dieser wird übersetzt und zu einer Executablezusammengebunden, die dann das Modell direktim Maschinencode in einem eigenen Prozess desBetriebssystems mit hoher Geschwindigkeit abar-beitet. Es wird eine Kommunikation mit Simulinkaufgebaut, über die die Abarbeitung gesteuert wer-den kann und Signale beispielsweise auf einemScope sichtbar sind. Hierbei werden intern keinemex64-dll mehr gerufen sondern der Code allerSfunction wird direkt eingebunden.

Aus den mex64-Files der Sfunctions werden auch

im Rapid-Accelerator die Initialisierungs-Teile be-nutzt. Das sind diejenigen C-Funktionen der Sfunc-tions, die auch beim Simulation - Update Diagramaufgerufen werden, siehe 10.2, seite 53.

Beim Accelerator-Mode wird zusätzlich auch dieC-Funktion mdlStart() aufgerufen. Das führtdazu, dass Speicherplatz allokiert wird. Dieserwird mit dem ebenfalls stattfindendem Aufruf vonmdlTerminate() wieder freigegeben.

Compiler- und Linker-Fehler

Der Ansatz der intensiven Nutzung von Sfunctionsmit gegebenenfalls wesentlichen C-Anteilen musssich in die Compilierung des Modells nahtlos einfü-gen. Wärend vorübersetzte und einzeln getesteteSfunctions im Normal-Mode der Simulation immerlaufen, kann beim Start des (Rapid-) AcceleratorMode doch einiges schief stehen, was zur Fehler-meldung ”Unable to build a standalone executableto simulate the model ’NAME’ in rapid acceleratormode.” führt. Es reicht bereits, wenn in einer zufäl-lig offenen C-Quelle unbemerkt einige falsche Tas-tenanschläge hineingeraten sind. Wichtig ist dieEinbindung der notwendigen zusätzlichen Quellenals C-Compilationseinheiten oder Verwendung vonLibraries mit den richtigen Compileroptionen über-setzt und stimmigen Versionen von Sources undHeaders, die Benennung von Include-Pathes undBeherrschung von Linker-Fehlern. Man hat hier al-so die gesamte Palette der Dinge, die vom Com-pilieren und Linken von C-Projekten bekannt sind,aber in einer anderen Umgebung. Wie bekannt giltauch hier die Regel: ”Wenn alles funktioniert dannist es sehr gut”. Das sollte nun auch die Voraus-setzung sein, wenn man sich eher auf die Simu-lation konzentrieren möchte als auf Compiler- undLinkerfehlermeldungen. Wenn es Probleme beimCompilieren und Linken gibt, die dann gelöst sind,dann verursacht eine Änderung des Modells unddamit nochmalige Compilierung in der Regel nichtwieder neue Probleme. Man kann also arbeitsteiligarbeiten. Ein Regelungstechniker arbeitet mit demModell, die Compiler- und Linkerprobleme werdenvom Informatiker zuvor gelöst.

Page 56: Simulink objektorientiert mit C-Kernfunktionen - Anleitung mit Demo- / Test-Version · 2019. 1. 2. · Simulink objektorientiert mit C-Kernfunktionen - Anleitung mit Demo- / Test-Version

11 ACCELERATOR- UND RAPID ACCELERATOR MODE 56

11.1 Ablageverzeichnis für Accelerator und Rapid Accelerator

Das Modell wird codegeneriert, der generierte Co-de wird temporär in ein eigenes Verzeichnis ge-schrieben. Man kann dieses Verzeichnis in eintemporäres separates Arbeitsverzeichnis legen,möglicherweise auf einer RAM-Disk bzw. auf demlokalen Datenträger, wenn ansonsten über Netz-werk gearbeitet wird. Die Quell- und Object-Fileskönnen so besser letztendlich gelöscht werden. Es

könnte ansonsten auch Probleme geben, wenn einZeitstempel falsch ist, bekannt vom make-Prozessbeim Compilieren. Das cleanup muss einfach zubewerkstelligen sein.

Ein abweichendes Verzeichnis ist im Simulink ein-stellbar, im Beispiel liegt es in einer als T: einge-richteten RAM-Disk:

Abbildung 6: Setzen temporäres Verzeichnis für Accelerator

Page 57: Simulink objektorientiert mit C-Kernfunktionen - Anleitung mit Demo- / Test-Version · 2019. 1. 2. · Simulink objektorientiert mit C-Kernfunktionen - Anleitung mit Demo- / Test-Version

11 ACCELERATOR- UND RAPID ACCELERATOR MODE 57

11.2 Welche Sources und Includepfade . rtwmakecfg.m

Das File rtwmakecfg.m muss vom Rapid accelera-tor builder aufgefunden werden. Dieses File wirdim selben Verzeichnis gesucht, in dem die Mex-Files der Sfunctions stehen. Findet der Builder dasrtwmakecfg.m nicht, dann gibt es bei Nutzung vonSfunctions die bekannte Fehlermeldung ”Unable to

build ...”.

Das File gehört zum Modell und wird daher - bishermanuell - dort gepflegt. Es soll dann im init-File desModells beim Start des Modells und beim Start derCompilierung in das mex-File kopiert werden. Da-zu enthält das init-File folgende Zeile:

system('copy "simulink\test\+TestOrthOscObjO\rtwmakecfg.m" mex\rtwmakecfg.m');

Das File rtwmakecfg.m muss den richtigen Inhalt haben, siehe folgend. Hinweis: Festgestellt in R2018b:"Zeichenketten" in Gäsefüßchen, dagegen bei früheren Versionen 'Zeichenketten' in Apostroph

function makeInfo = rtwmakecfg()

%Absolute paths are necessary because the working dir for rapid accelerator can ...

%Settings in Simulink preferences, General, simulation cache folder.

rootPath = evalin('base', 'rootPath'); %It is the root for the Simulink session,

gensrcPath = evalin('base', 'genSrc'); %It is the path for all DataStructMng_Inspc

emcPath = "D:/vishia/emc"; %The full emc sources

%Text to detect in diagnostic viewer output:

disp("======= rtmakecfg - lib_emC ==============================");

%Include path for the rapid accelerator compilation

makeInfo.includePath = ...

{ fullfile(emcPath, "incApplSpecific/stdef_SmlkAccelerator") ...

, fullfile(emcPath, "incComplSpecific/cc_SmlkSfunc_64bit") ...

, fullfile(emcPath, "source") ...

, emcPath ...

, fullfile(rootPath, "test/+MyModel/srcC") ... %special sources for this model

, fullfile(rootPath, gensrcPath) ...

};

%if sources are named in the tlc-file they are searched in the following paths.

%Only if the source is found, a compilation is started, elsewhere the obj ...

%Hint: The sources are written in the tlc file with the 'Fileset srcTlc_... = ...'

% in the +mkSfn/...m wrapper generation script.

makeInfo.sourcePath = ...

{ fullfile(rootPath, "test/+MyModel/srcC") ... %special sources for this model

};

%Additional libs for the rapid accelerator linking

makeInfo.linkLibsObjs = ...

{ fullfile(rootPath, "lib/mex/libMsc15_emC.lib") ...

};

end

Die Display-Ausgabe der ersten Zeile ist im Dia-gnostic Viewer - Ausgabe des Ablaufes der Com-pilierung - wieder auffindbar. Der includePath wird

benutzt für die Compilierung des Modells, adäquatwie die mex ... -Iincludepath - Zeilen beim Auf-ruf der Sfunction-Generierung.

Page 58: Simulink objektorientiert mit C-Kernfunktionen - Anleitung mit Demo- / Test-Version · 2019. 1. 2. · Simulink objektorientiert mit C-Kernfunktionen - Anleitung mit Demo- / Test-Version

11 ACCELERATOR- UND RAPID ACCELERATOR MODE 58

Der sourcePath wird benutzt, um die zusätzlichenSources aufzufinden, die in den tlc-Files benannt

sind.

Page 59: Simulink objektorientiert mit C-Kernfunktionen - Anleitung mit Demo- / Test-Version · 2019. 1. 2. · Simulink objektorientiert mit C-Kernfunktionen - Anleitung mit Demo- / Test-Version

11 ACCELERATOR- UND RAPID ACCELERATOR MODE 59

11.3 Zusätzliche Libraries beim Rapid Accelerator einbinden

Die linkLibsObjs-Angabe im rtwmakecfg.m-Filebenennt Libraries, die beim Linken mit beachtetwerden. Man hat hier nun die Möglichkeit, vorüber-setzte Quellen zu benutzen. Im Beispiel wird dieWindows-Socket-Library ws2_32-lib extra ange-

geben, dazu die selbst erstellte emC_SmlkAccl.lib,die die gesamte Umgebung der CRuntimeJavalike,insbesondere die umfangreichen Quellen des In-spector in compilierter Form bereitstellt.

Diese Library wird mit einem JZcmdScript erstellt:

java.exe -cp ../zbnfjax/zbnf.jar org.vishia.jztxtcmd.JZtxtcmd %0 -t:_gen.bat

if errorlevel 1 goto :error

echo call make\_gen.bat

call _gen.bat

.....

exit /B

==JZtxtcmd==

include ../../../Jc/CRuntimeJavalike/make/JZtxtcmd/Msc.zmake.jztc;

String srcDir=<:><&scriptdir>/../../../Jc/CRuntimeJavalike<.>;

String objDir = "T:\libAccel.obj"; ##<:><&$OBJDIR><.>;

Fileset includePath =

( ../../../Jc/CRuntimeJavalike/incApplSpecific/stdef_SmlkAccelerator

, ../../../Jc/CRuntimeJavalike/incComplSpecific/cc_SmlkSfunc

, ../../../Jc/CRuntimeJavalike

, ../../../Jc/CRuntimeJavalike/source

, ../../../Jc/CRuntimeJavalike/source/OSAL

);

Fileset src_make=

( source:Fwc/*.c

, source:Jc/*.c

.....

);

String compileOptions=<:>-c -DCRTAPI1=_cdecl ......<.>;

zmake "mex/emC_SmlkAccl.lib" := cc("../../Jc/CRuntimeJavalike" &src_make, =.....

zmake "mex/emC_SmlkAccl.lib" := clib("../../Jc/CRuntimeJavalike" &src_make, .....

Das File ist nur in Auszügen angegeben, sieheBeispiel Example_ObjO.zip im PfadmakeSmlkLibs/zmake_emC.Accel.lib.bat. Mankann die Library auch mit einem Standard-make-File erzeugen und hat letztlich die ad-äquaten Angaben zu machen. Die Compiler-optionen wurden aus der Compilerausgabe ko-

piert, die im Diagnostic Viewer beim Start desAccelerator mode auch für die anderen Com-pileraufrufe (des Modellfiles) gelten. Somit istsichergestellt, dass die Optionen zueinanderpassen. Das Make-System mit zmake ist aufhttp://www.vishia.org/docuZBNF/Zmake.html er-läutert.

Page 60: Simulink objektorientiert mit C-Kernfunktionen - Anleitung mit Demo- / Test-Version · 2019. 1. 2. · Simulink objektorientiert mit C-Kernfunktionen - Anleitung mit Demo- / Test-Version

11 ACCELERATOR- UND RAPID ACCELERATOR MODE 60

11.4 tlc-Files

Die tlc-Files (files für den target languagecompiler werden sowohl bei der Zielsystem-Codegenerierung benutzt, als auch jeden-falls für den Rapid Accelerator Mode und fürden Accelerator-Mode bei gesetzter OptionSS_OPTION_USE_TLC_WITH_ACCELERATOR in derSfunction. Ein tlc-File enthält die Vorschrift zurBildung des C-Codes für die einzelnen Pha-sen (start, init, run). Diese sind in einer eige-nen tlc-Scriptsprache hinterlegt. Die C-Code-Bildungsvorschrift kann Variablennamen, C-Funktionsaufrufnamen und Comments im Klartextenthalten, die im generierten Zielsystemcode wie-dergefunden werden können und so der Orientie-rung im generiertem Code dienen können. Bei denC-Codes für den Accelerator werden Commentsausgeblendet.

Die tlc-Files werden von der Sfunction-Generierung über das JZtxtcmd-Script generiert.Damit bestimmt der Inhalt der JZtxtcmd-Scriptsden Inhalt der tlc-Files.

Im tlc-File steht auch, welche zusätzlichen Quel-len und Libraries für eine S-function eingebundenwerden muss, neben den Codes im tlc-File. Die-se Information wird aus dem Generier-Steuerscript(siehe S. 47) aus der Abteilung

Fileset srcTlc_MyHeader = ( ... );

Fileset lib_MyHeader = (.... );

entnommen. Der Suchpfad zu diesen Quellen undLibraries steht dann im rtwmakecfg.m, siehe vorigeSeite.

Beispiel: Das Generier-Steuerscript enthält:

Fileset srcTlc_AngleBlocks_FB =

( srcc_FB/AngleBlocks_FB.c

, gensrc_Refl/AngleBlocks_FB_crefl.c

);

## All sources for compilation

Fileset src_AngleBlocks_FB =

( &srcRaccl_AngleBlocks_FB

, emC/source/Fwc/fw_Reflect....c

......

);

Diese Angaben werden in das tlc-File übertragen,dabei nur die srcTlc_.... Die anderen Sourcesmüssen über die Library gefunden werden.

Dazu der passende Ausschnitt aus dem generier-ten tlc-File:

%function BlockTypeSetup(block, system) void

%%

%% The Target Language must be C

%if ::GenCPP==1

%<LibReportFatalError("This S-Function must be only used with the C Target Language")>

%endif

%%For compilation: All headers which should be included:

%<LibAddToCommonIncludes("Fwc/fw_handle_ptr64.h")> %%Always used.

%%Note: It is taken from the input header file,the local file part.

%<LibAddToCommonIncludes("AngleBlocks_FB.h")>

%%For accelerator: All compilation units (C-files) which should be add to the exec.

%%Note: It is taken from set srcRaccl_AngleBlocks_FB from the user's start script,

%%only file names, not with path:

%%

%<SLibAddToStaticSources("AngleBlocks_FB.c")>

%<SLibAddToStaticSources("AngleBlocks_FB_crefl.c")>

%%

%endfunction

Page 61: Simulink objektorientiert mit C-Kernfunktionen - Anleitung mit Demo- / Test-Version · 2019. 1. 2. · Simulink objektorientiert mit C-Kernfunktionen - Anleitung mit Demo- / Test-Version

11 ACCELERATOR- UND RAPID ACCELERATOR MODE 61

11.5 Auswahl des Compilers und XML-Steuerdatei für die Compilierung

Die Auswahl des Compilers für Simulink erfolgt mitder Aufrufzeile im Matlab

mex -setup

Matlab sucht dann nach installierten Compilern,wählt automatisch den einen installierten Compi-ler aus oder bietet eine Auswahl an. Entsprechenddem Compiler wird eine XML-Datei im Windows-Userbereich angelegt und gefüllt, die Informatio-nen über den Compiler, Include- und Librarypfade,voreingestellte Compileroptionen und dergleichenenthält.

Man kann diese XML-Datei dann anpassen, wennder betreffende Compiler nicht direkt vorgesehenist, andere Compileroptionen notwendig sind oderbeispielsweise Linkerfehler wegen fehlender Libra-ries auftreten. Hierbei sollte die entsprechendeSachkenntnis über Compileraufrufe und etwas Ex-perimentierzeit vorhanden sein. Dieses XML-Fileist beispielsweise unter

c:\Users\hartmut\AppData\Roaming\

MathWorks\MATLAB\R2017b\mex_C_win64.xml

aufzufinden.

Mit einem Beispiel sollen folgend die Möglichkeitenaufgezeigt werden:

Beim Anwender wurde Microsoft Visual Studio2017 als sogenannt Community-Version installiert.Diese kostenfreie Version ist etwa für die Open-Source Entwicklung gedacht.

Bei Aufruf des Visual Studio Compilers wird ein FileVCVARSALL.BAT aufgerufen, das sich im Filebereichdes Compilers befinden und verschiedene Umge-bungsvariable für den Aufruf des Compilers setzt.Dieses File ist in der XML-Datei aufgeführt als:

CommandLineShell="c:\Programs\Msc17\Commu

nity\VC\Auxiliary\Build\VCVARSALL.BAT "

Mit der Community-Version hat nun dieses Batch-File gleichzeitig ein cd (change directory) zur Lo-cation c:\users\hartmut\source ausgeführt. Eineauf einem anderen PC vorhandene Professional

Version 2015 hat dies nicht ausgeführt. Ergebnisbeim Accelerator-Aufruf gab es die Fehlermeldung:

NMAKE : fatal error U1052: file

'TestOrthOscObjO.mk' not found

Das makefile war aber vorhanden. Dass die Aus-führung von VCVARSALL.BAT das Problem verur-sacht, wurde erst mit einigen Experimenten er-kannt.

Abhilfe ist nun, der Austausch der Zeile im XML-File

CommandLineShell=

"c:\BATCH\VCVARSALL_A.BAT "

Dieses manuell geschriebene File ruft letztlich dieVCVARSALL.BAT auf, umkleidet aber diesen Aufrufmit

set PWD1=%CD%

call c:\Programs\Msc17\Community\VC\

Auxiliary\Build\vcvars64.bat

...

cd /D %PWD1%

echo %CD%

und stellt damit das richtige Verzeichnis wieder ein.

Ein anderes Problem waren fehlende Libraries indieser Version, die mit Erweiterung des Library-Path nach Installation des Microsoft Software De-veloper Kit 8.1 bereitgestellt werden konnten:

LINKLIBS="/LIBPATH:&quot;$MATLABROOT\....

/LIBPATH:c:\Programs\WinSDKv8.1\Lib\x64

Es ist zu empfehlen, von Anfang an auf eine Pro-fessional Edition des Compilers zu setzen bei derkeine Anpassungen notwendig sind.

Hinweis: Für die einfache Accelerator-Übersetzungbringt Simulink intern einen passenden Compi-ler für Windows mit (lcc64). Auch ein MinGW-Compiler ist nutzbar. Das Visual Studio ist dannnotwendig, wenn in den Sfunction-Quellen gebug-ged werden soll.

Page 62: Simulink objektorientiert mit C-Kernfunktionen - Anleitung mit Demo- / Test-Version · 2019. 1. 2. · Simulink objektorientiert mit C-Kernfunktionen - Anleitung mit Demo- / Test-Version

11 ACCELERATOR- UND RAPID ACCELERATOR MODE 62

11.6 Wie kann man Fehler erkennen und beheben?

Beim Start des Rapid Acclerator Mode wird im Dia-gnostic Viewer -Fenster sehr konkret Compiler- undLinkerfehlermeldungen angezeigt. Der DiagnosticViewer klappt automatisch auf, wenn es zu ”Unableto build ...” kommt. Man kann dieses Fenster unab-hängig von der Fehlermeldung öffnen durch Klickauf einen Link, der während des Build-Prozess inder unteren Statusleiste des Modells erscheint. ImDiagnostic Viewer ist anwählbar, ob man Errors,Warings oder Infos sehen möchte, Icon oben. Diedetailierten Compiler- und Linkerfehler kommen alsInfo.

Gibt es Compilerfehler, dann sind diese wie ge-wohnt in den Quellen zu korrigieren. Zu beach-ten ist, dass der Compiler je nach Einstellung nichtC++ sondern C compiliert. Es hängt vom verwen-deten Compiler des Rapid Accelerator Mode ab,wie C-Dialekte verarbeitet werden.

Wichtig ist die richtige Wahl der Include-Pathes,enthalten in der rtwmakecfg.m.

Linkerfehler gibt es wenn Quellen nicht benannt

worden sind, oder auch wenn Compileroptionennicht stimmen. Das ist bekannt vom C/C++-Build-Prozess und gilt auch hier. Das Kapitel ?? Seite ??enthält Hinweise wie eine Library zu bilden ist.

Es verbleiben aber noch die Fehler zur Laufzeit.Enthält der C-Code Laufzeitfehler und diese wur-den nicht beim Vortest und beim Test der Sfuncti-ons entdeckt, dann kann es einen Absturz geben.Hier hilft dann nur nochmals in den Vortest zu ge-hen. Das ist auch bekannt in der normalen C/C++-Entwicklung ohne Simulink.

Arbeitsteilig arbeiten: Der Simulink-Entwicklermöchte nichts mit den Compiler/Linker-Problemen zu tun haben!

Dies ist auch zu empfehlen, wenn ein und diesel-be Person die C-Entwicklung betreibt und dannin Simulink das Gesamtprojekt testet. Wichtigist also ein Vortest, bevor die eigentliche Kern-Funktionalität, die im Simulink-Modell auch ent-sprechend variiert werden kann, in den Fokus desTests kommt.

Page 63: Simulink objektorientiert mit C-Kernfunktionen - Anleitung mit Demo- / Test-Version · 2019. 1. 2. · Simulink objektorientiert mit C-Kernfunktionen - Anleitung mit Demo- / Test-Version

12 SOFTWARE IM ZIELSYSTEM MIT GENERIERTEN SIMULINK-CODES 63

12 Software im Zielsystem mit generierten Simulink-Codes

TODO

Page 64: Simulink objektorientiert mit C-Kernfunktionen - Anleitung mit Demo- / Test-Version · 2019. 1. 2. · Simulink objektorientiert mit C-Kernfunktionen - Anleitung mit Demo- / Test-Version

13 BEOBACHTEN UND EINGREIFEN MIT DEM INSPECTOR 64

13 Beobachten und Eingreifen mit dem Inspector

Im Simulink ist es gängige Praxis, bei Bedarfalle internen Daten darzustellen und bestimm-te Daten (Parameter, Konstante) zu verändern.Dies ist schon deshalb notwendig weil Simulinkein Entwicklungswerkzeug der Regelungstechni-schen Algorithmen ist. Mit dem Kapseln der Kern-Funktionen in C ist es trotz des unterstelltenBlackbox-Charakters dieser Funktionsblöcke den-noch wünschenswert, deren Daten zu sehen. Diesist auch gängige Praxis der Objektorientierung: Sa-ge mir Deine Daten, und ich weiß was Du bistkönnte als Leitspruch der Erkenntnis über Klassengelten. Die Daten sind zwar für den Zugriff private

gekapselt, aber die Darstellung auch der private-Attribute im Klassendiagramm der OOP gibt dennotwendigen Überblick.

Dem Ansinnen, auf die private-Daten der Object-FB zuzugreifen kommt eine Technik entgegen, dievom Verfasser mit Seitenblick auf Java in der Ver-gangenheit entwickelt wurde und sich in der Pra-xis bestens bewährt hat: Zugriff über Reflection,mit dem Tool und Protokoll des Inspectors. DieseTechnik auf Simulink angewendet gestattet nichtnur den Zugriff auf die private-Daten der Object-FBs von außen, sondern insgesamt:

13.1 FBs für den Inspector im Simulink

GetValue_Inspc

Dieser FB speziell für Simulink gestattet das Her-auslegen von Daten aus C-FunctionBlocks bei-spielsweise zum Anschluss an einen Scope, alsMesspunkt oder numerische Anzeige (Display). Eswäre möglich die Daten auch im Modell funktio-nal zu verwenden. Dies kann zweckmäßig seinfür Test-Auswertungen, nicht aber für die Core-Funktonalität, die damit über eine zweite Ebeneneben der modellmäßigen Datenhaltung arbeitenwürde. Im Zielsystem (über Codegeerierung) kanndieser FB ebenfalls für Debugzwecke eingesetztwerden, wenn beispielsweise eine Analogausgabefür Tests damit gemapped wird.

Der Datenpfad wird symbolisch angegeben, wir erbeim Zugriff mit dem Inspector gilt. Er wird beimStartup einmalig gelesen. Damit wird die Speicher-adresse der Variablen ermittelt. Zur Runtime wirddann der Wert der Variable auf den Output gelegt.

Abbildung 7: Einsatz GetValue_Inspc

Die derzeitige Realisierung des FB hat 6 Ausgängefestgelegt auf float bzw. single. In Vorbereitung: Typund Anzahl von Arrayelementen wird in der Para-meterangabe für den Datenpfad mit berücksichtigt,adäquat zum FB TimeSignalFloat_Inspc.

Page 65: Simulink objektorientiert mit C-Kernfunktionen - Anleitung mit Demo- / Test-Version · 2019. 1. 2. · Simulink objektorientiert mit C-Kernfunktionen - Anleitung mit Demo- / Test-Version

13 BEOBACHTEN UND EINGREIFEN MIT DEM INSPECTOR 65

InputValuesC_Inspc

Abbildung 8: Einsatz InputValuesC_Inspc

Dieser FB gestattet das Einlesen vonSignalwerten aus dem Modell für denInspector-Zugriff. Er ist gedacht nichtfür die Modellteile, die über Codegene-rierung im Zielsystem verwendet wer-den, sondern speziell für die Simulink-Modellteile der Umgebungssimulation,die meist direkt im Simulink nicht überSfunctions realisiert werden, beispiels-weise unter Nutzung von Simscape. DerFB hat 12 Eingänge belegbar mit Simulink-Signalen, auch Vektoren und komple-xe Werte. Der Typ der Eingänge wirdaus der Verdrahtung im Modell herauserkannt. Es werden intern Reflection-Informationen aufbereitet, die dann fürden Inspector-Zugriff über Reflection ge-nauso wie in Sfunctions oder im Ziel-system genutzt werden. Im FB wird denSignalen ein entsprechender Name ge-geben. Der FB ist als Node in einenBaum eingeordnet.

TimeSignalsFloat_Inspc

Abbildung 9: Einsatz TimeSignalsFloat_Inspc

TimeSignalsBits_Inspc

Mit diesen beiden FB werden Signal-Werte für das Modell vorgegeben. Ähn-lich wie der InputValuesC_Inspc ist diesfür die Nicht-Zielsystem-Modellteile ge-dacht. Der FB ist eine Kombination ausdem Inspector-Zugriff und einer internorganisierten zeitgesteuerten Vorgabe.Letztere holt sich beim Startup die Zeit-Wert-Informationen aus einem File, spe-ziell gedacht für Testserien oder aberauch als Anfangswertvorgabe. Man kanndie Werte mittels Inspector überschrei-ben, bis zu dem Zeitpunkt an dem sieper File neu definiert werden. Typischer-weise werden oft Anfangsbelegungenvorgegeben, die dann dauerhaft über-schrieben werden können da sie per Zeitsteuerung nicht wieder neu gesetzt werden. Es gibt 2 Typenvon FBs: Für Float-Ausgänge und für Boolean. Die Float-Variante kann pro Ausgang für Vektoren bismax. 6 Elemente und für komplexe Größen konfiguriert werden.

Page 66: Simulink objektorientiert mit C-Kernfunktionen - Anleitung mit Demo- / Test-Version · 2019. 1. 2. · Simulink objektorientiert mit C-Kernfunktionen - Anleitung mit Demo- / Test-Version

13 BEOBACHTEN UND EINGREIFEN MIT DEM INSPECTOR 66

Wait_Inspc

Dieser FB ist nur einmal im Modell anzuordnen, da-her hier gleich neben dem zentralen Service _In-spc gezeigt. Der FB zählt die Zyklen ab Start undschaltet danach in einen Stop- oder Delaymodus.Stop wird mit der Angabe 0 für delay erzeugt. Da-bei steht die Simulink-Abarbeitung, sie hängt imFB. Das ist dazu gedacht, nunmehr mit dem In-spector beispielsweise neue Werte für Simulis vor-zugeben. Nachdem dies erfolgt ist, manuell oderper Inspector-Tool-Script, wird ebenfalls über denInspector-Zugriff ein erneuter Stop-Punkt vorgege-ben. Mittels vorgabe von2000000000 steps (etwa der maximale Integer-Bereich) läuft die Simulation dann quasi dauerhaft.

Abbildung 10: Einsatz Wait_Inspc

Die Wait-Variante hilft, eine schnelle Simulation so zu entschleunigen, dass einzelne Verläufe manuellgut beobachtbar sind. Die Scopes laufen dann auch automatisch langsamer. Es wird im FB in derangegebenen Abtastzeit ein delay über das Betriebssystem erzwungen. Auch hier hilft eine Vorgabeder cycles >0 um wieder volle Geschwindigkeit zu erhalten bis zur erneuten Stimuli-Vorgabe.

RegisterNode_Inspc_A.png

Dieser FB ist das entscheidende Bindeglied zwi-schen den Object-FB-Sfunctions und dem Inspec-tor. Es wird im Modell außerhalb der Teile einge-setzt, die im Zielsystem codegeneriert erscheinensollen, und zwar direkt an deren Ausgang. Dort sollein Handle-Ausgang bereitstehen, der die Intern-Daten repräsentiert.

Im Zielsystem mit Einsatz der Reflection wird die-ser Handle bzw. die Speicheradresse direkt in denReflection-Tree aufgenommen, in der Umgebungzum generierten Zielsystemcode. Das geschiehtfür die Simulink-Ebene mit diesem FB adäquat.

Abbildung 11: Einsatz RegisterNode_Inspc_A.png

Zum FB werden 2 Namensteile angegeben. Die Namensteile sind dann wichtig, wenn ein Namensteilüber eine Variable für mehrere Instanzen geregelt wird.

Page 67: Simulink objektorientiert mit C-Kernfunktionen - Anleitung mit Demo- / Test-Version · 2019. 1. 2. · Simulink objektorientiert mit C-Kernfunktionen - Anleitung mit Demo- / Test-Version

13 BEOBACHTEN UND EINGREIFEN MIT DEM INSPECTOR 67

Service_Inspc_A.png

Abbildung 12: Einsatz ServiceNode_Inspc_A.png

Dies ist der zentrale FB für den Inspector-Service.Er wird mit der IP-Adresse parametriert.

13.2 Zugriff mit dem Insspector

Der Inspector als Tool greift über Socket-Kommunikation auf den zentralen FB Ser-vice_Inspc zu, mit der dort angegebenen IP-Adresse mit Port-Nummer (IP V4). Wenn der In-spector auf dem selben PC läuft ist die Kommu-nikation über local-host (loop back) sehr schnell.Über eine Netzwerkkarte mit Ethernet sind Zugriffeim 1 ms-Raster möglich. Mit dem Inspector könnendie Daten nicht nur visualisiert werden. Es werdenfolgende Funktionen bereitgestellt:

• Zugriff auf die Daten insbesondere auchwenn die Simulation gestoppt ist.

• Zugriff auf die Daten über die Baumstruktur,Zugriff auf Einzeldaten bei Bedarf, lesen undschreiben.

• Aufbau von Bildern (Datendarstellung) mitnumerischen Werten und möglicher Hinter-grundgrafik, gesteuert mit einem Script. Essind sowohl verschiedene Bilder als Laschenanwählbar als auch Sub-Fenster aufklapp-bar. Damit ist zusätzlich zu den Möglichkei-

ten im Simulink-Modell eine Datenübersichtüber das Gesamt-Modell möglich.

• Setzen bestimmter Daten in einer Datendar-stellung, über numerische Eingabe oder But-ton für Einzelbits.

• Darstellung des zeitlichen Verlaufs der Daten(Curve-View).

• Speicherung der Daten des zeitlichen Ver-laufs

Diese Möglichkeiten sind in der gleichen Wei-se auch im Zielsystem unterbringbar. Damitergibt sich ein konformer Zugriff auf die Datenim Simulink-Modell als auch dann im Zielsystem.Wenn die Daten in gleicher Art in den Reflection-Tree eingeordnet sind, sind selbst die Datenpfadeidentisch. Damit brauchen die Scripts für die Da-tendarstellung nicht doppelt gepflegt werden bzw.können bereits in der Simulationsphase erarbeitetwerden.

13.3 Das Reflection-Prinzip

Von allen struct-Definitionen in den Headerfi-les werden Reflection-Informationen erstellt. Die-se sind in C const-Datenstrukturen und enthaltenName, Type und Offset in der struct. Bei der Ge-nerierung der Sfunctions werden C-files mit dieserKonstantendefinition abgelegt, wenn als zmake si-mulinkSfuncBusGen-Aufruf-Argument dirRefl an-gegeben wird, siehe Kapitel 9, Seite 46. Die Exten-sion dieser Files ist .refl.c.

Die Daten der Inspc-FunctionBlocks (InputValue-sC_Inspc usw.) sind in gleicher Art organisiert, nur

dass hier der Aufbau der Daten mit den angegebe-nen Parametern im FunctionBlock im RAM erfolgt.

Die Reflection-Infos (Typ ClassJc) sind in einemBaum organisiert. Das ist damit gegeben, dassReferenztypen als Referenz auf die entsprechen-de Reflection-Info (ClassJc) angegeben ist. Esgibt eine root-struct, die im FB Service_Inspcverankert ist und im Simulink zur Laufzeit mitden angehangenen Inspc-FBs gebildet wird: In-putValuesC_Inspc, TimeSignalBits_Inspc, TimeSi-gnalFloat_Inspc und RegisterNode_Inspc vorge-

Page 68: Simulink objektorientiert mit C-Kernfunktionen - Anleitung mit Demo- / Test-Version · 2019. 1. 2. · Simulink objektorientiert mit C-Kernfunktionen - Anleitung mit Demo- / Test-Version

14 LITERATUR, QUERVERWEISE 68

geben sind. Wenn im Zielsystem eine entspre-chende Root-struct angelegt ist, als Laufzeitum-gebung, erhält man im Zielsystem den vergleich-baren Baum-Aufbau.

Es ist möglich, dass aggregierte Daten aufstruct ObjectJc basieren und eigene Reflection-Information haben. Damit kann der Typ der Ag-gregation ein Basistyp sein (im einfachten FallObjectJc), das Aggregat kann ein abgeleiteter Typ

sein. Das wird ausgenutzt um die Vererbung imOOP-Sinn zu unterstützen. Wenn die aggregiertenDaten nicht auf ObjectJc basieren und damit keineeigenen Reflection-Informationen mit sich bringen,dann sind die Reflection-Informationen mit demTyp der Referenz identisch. Für die Object-FBs alsSfunctions gilt nun, dass diese auf ObjectJc basie-ren müssen, für den Typtest des Handle. Dies hilftnun auch gleichzeitig für den Typ der Reflection.

13.4 Das Inspector-Tool

Der Inspector ist ein in Java geschriebenes Tool. Im Zipfile Example_ObjO_Smlk.zip ist eine jar-Libraryenthalten, die für Java-8 (Oracle) compiliert ist. Der Aufruf des Inspectors ist dort mit ...TODO

14 Literatur, Querverweise

Die Simulink-Funktionen sind über die Simulink-Toolhilfe in einer lokalen Installation und im Internetauffindbar und sind daher nicht extra als Literaturquelle extra aufgeführt.

Ebenfalls als bekannt und verbreitetet oder auffindbar vorausgesetzt sind die Theorien und Praktikender UML (Unified Modelling Language) und der OOP (ObjectOriented Programming).

Die konkrete Implementierung des hier gezeigten Beispieles getestet mit Mathworks, Simulink Versi-on 2016a sind auf der Internetseite www.vishia.org/Smlk/Download enthalten, Erläuterungen dazu aufwww.vishia.org/Smlk/html/OOPinSimulink.html. Diese Seite wird vom Verfasser erstellt und gepflegt.