per Reference C++, per Pointer C, C++

Grund
Will man mehrere externe Variable in einer Funktion bearbeiten, hat aber nur einen return Wert, so gibt man die Adressen dieser Variablen als Paramter mit. Dadurch wird die Variable direkt durch die Funktion bearbeitet. (Die Alternative wäre, globale Variablen zu definieren und diese zu übergeben. Da globale Varibalen vermieden werden sollen, entfällt diese Alternative.)

Pointer übergeben (C und C++)

function(int *x){do someting}    // Deklaration: Parameter ist ein Pointer

int a ;
function(&a);                    // Argument: Adresse der Variable

Bei der Übergabe per Pointer, wird keine lokale Kopie des Arguments erstellt, sondern die Änderungen werden direkt in den Speicher geschrieben.

Per Reference übergeben (C++)

function(int &x);           // Deklaration: Parameter einer Variable per Ref.
int a;
function(a);                // Die Adresse des Arguments wird genommen

Bei per Reference geschieht das selbe wie beim Pointer. Nur sieht man es beim Argument nicht direkt. Die Variable wird „normal“ übergeben.
Trotzdem ist die Wirkung die selbe wie bei der Pointerübergabe: Wie bei einer gobalen Varibale wird durch die Funktion die externe Variable verändert (LINK)

ASCII to binary

Wird einem char eine Zahl zugewiesen, so entspricht dies nicht der binären Darstellung !

int a = 16            0001 0000
char b = ‚16′         0011 0001    0011 0110     sind zwei Ascii-Zeichen
char c = ‚1‘            0011 0001
char d = ‚6‘           0011 0110
int d = 6             0000 0110

Lösung
char c = ‚1‘ – ‚0‘    0000 0001
Will man einen Char, der die Zahl binär darstellt, so muss man den char-Wert ‚0‘ abziehen. Die Hochkommas sind zwingend, da sonst ein Typcast (zu int) vollzogen wird.

Cmake introduction

Automatisches Generieren von Makefiles

$ mkdir build
$ cd build
$ cmake ..   // führt die CMakeList.txt aus = generiert Makefiles
             // cmakeList.txt liegt ein Verzeichnis weiter unten
$ make       // führt die Makefiles aus

Mit cmake werden Makefiles generiert. Alle Makefiles liegen im Ordner build. Alle Dateien, die die Programme zur Ausführung brauchen, müssen im build liegen.

Mehrere Executables

CMAKE_MINIMUM_REQUIRED(VERSION 2.6)
PROJECT(HuffmanDecoder)

ADD_DEFINITIONS("-std=c++11 -g")

ADD_EXECUTABLE(decoder
    main.cpp
    FileStreamReader.cpp
    HuffmanDecoder.cpp
    BinaryTree.cpp
    EndoscopeImage.cpp
)

ADD_EXECUTABLE(decoder_fullversion
    decoder.cpp
    FileStreamReader.cpp
    HuffmanDecoder.cpp
    BinaryTree.cpp
    EndoscopeImage.cpp
)

ADD_EXECUTABLE(encoder
    encoder.cpp
    FileStreamReader.cpp
    HuffmanDecoder.cpp
    BinaryTree.cpp
    EndoscopeImage.cpp
)

ADD_EXECUTABLE(testTree
    testTree.cpp
    BinaryTree.cpp
)

Will man nur ein bestimmtes Projekt kompilieren, schreibt man:

$ make testTree && ./testTree

Durch && ./executalbe wird das Programm direkt ausgeführt.

 

Referenzen im Netz

Link1: Anleitung für Programmiererinnen

Link2: Einfache Einführung

Make bedeutet kompilieren (und linken). Will man mehrere Dateien kompilieren und dann auch linken, genügt ein einfacher Shell-Befehl gcc -o main.c test  nicht mehr. Man macht dann ein Makefile, in dem durch Pfad-Variablen und Variablen der Datein, das Kompilieren, Linken vereinfacht wird.

Die Aufgabe von Cmake ist es, Makefiles automatisiert zu erstellen. Der Aufruf cmake funktioniert nur, wenn im Zielordner auch die Datei CMakeLists.txt liegt. In jedem Unterordner liegt eine CMakeLists.txt

cmake pfad/zu/dateien

Alle wichtigen Ergebnisse des Kompilieren, Linkens legt das Programm selbständig in diese Datei ab.

………………………………………………………………………………….

Projektstruktur
project /  CMakeList.txt                          // das main CMake
.                 / source /  CMakeList.txt      // jeder Unterordner braucht sein CMake
.                                     main.cpp
.                                      classb.cpp
.                  /build/                                        // nur hier kein CMakeList.txt
.

Erhält man ein Programm aus einer Plattform, wird das Programm oft so gebildet:

$ mkdir build
$ cd build
$ cmake ..   // führt die CMakeList.txt aus = generiert Makefiles
$ make       // führt die Makefiles aus

 

……………………………………………………………………………………….

CMake legt auch eine CMakeCache.txt Datei selbständig an. Darin sind alle Konfigurationen gespeichert. Diese Datei sollte nicht manuell geändert werden.

Das Programm wird oft nicht im Ordner der Quelldateien abgelegt. Man kann einen Ordner build angeben oder /user/bin nehmen.


Hauptdatei: CMakeLists.txt

add_executable(hallowelt main.c)

Hat man mehrere Files, so werden diese in einer Varibale zusammengefasst

SET( SOURCE main.c calculator.c)   Mit set werden Variablen gesetzt

Braucht man später die Variable, so geschieht dies mit ${SOURCE}  .

add_executable(calculator ${SOURCE})

PROJECT( name )
INCLUDE_DIRECTORY( /usr/bin )
TARGET_LINK_LIBRARIES()
ADD_DEFINITIONS()

INSTALL( TARGETS <programm> RUNTIME DESTINATION bin)

 

Variable zu bereits bestehenden Variablen hinzufügen

SET( EXTRALIBS ${EXTRALIBS} /usr/local/bla)
Fett stehen hier alle alten Pfade zu Bibliotheken, danach kommt der neue Pfad.
Ein typisches Beispiel ist die Umgebungsvariable PATH. Dort wird auch zu ${PATH} <neuer Pfad> dazugeführt.

..

yocto: Konzept und Literatur

Yocto ist ein Build-System und hilft, ein embedded Linux-System aufzubauen.

 

Konzept

  • Yocto stellt eine Referenz-System (Poky), durch das viele Tools und Projekte leicht einbaubar sind zur Verfügung.
  • Unter den Cores besteht eine offene Struktur (Metadaten). Dadurch besteht Kompatibilität unter diversen Projekten
  •  Einfaches Buildprogramm (Bitbake), dass mit dieser offenen Struktur umgehen kann und Images buildet.

Wegen dieser Offenheit, können viele BSP (Board Support Packets) der Hersteller eingebunden und weiterentickelt werden. Dadurch muss das Build-System nicht neu erfunden werden.
BSP: Altera stellt über Quartus BSP für FPGAs her. Diese können relativ einfach in Yocto integriert werden. (Device Tree generieren, aus Datei.sof -> Datei.rbf und einen Preloader hinzufügen.)

 

Notwendige Grundlagen-Dateien
Auf dem Speichermedium, vom dem aus gebootet wird, liegen neben dem Yocto-Image weitere Dateien. Yocto ergänzt nur diese Dateien (mit seinem zImage), bzw. hilft, die Grundlagen-Dateiene zu einem funktionstüchtigen Gebilde zusammenzufügen.

  • Bootloader (Image)
  • Bootscript  -> nur so ist das System startfähig
  • Kernel mit Devicetree
  • File System (Image)

 

Struktur Yocto Projekt
-> Ordner build/
conf/                                          layers einstellen,
….

-> ordner pocky/
bitbake/
documentation/
meta/
meta-yocto/
meta-yocto-bsp/                               scripts/                                      um neue Projekte beizufügen
(layers)

Image builden

cd build
bitbake virtual/bootloader
bitbake virtual/kernel
bitbake core-image-minimale     // root file System

 

Vorteile

Die Vorteile von Yocto liegen laut der Linux Foundation darin, dass viele Vorlagen für die Unterstützung spezifischer Hardware (Board Support Packages) vorhanden sind und es einfach ist, das System auf neue Hardware zu portieren. Auch in Lizenzfragen ist man mit Yocto auf der sicheren Seite.

Bücher

  • Embedded Linux Projects Using Yocto Project Cookbook, March 2015
    By Alex González

https://www.packtpub.com/application-development/embedded-linux-development-yocto-project

Board Support Package (BSP)

Normalerweise genügt eine Distribution, um ein Linux laufen lassen zu können. Im Embedded Bereich jedoch sind die Komponenten stark optimiert, so dass spezifischen Treiber, zusätzliche Bibliothekten etc. eingebaut werden (Überblick bei Linutronix.)

Eine gute Unterstützung beim Erstellen eines BSP bietet Yocto.

Die modernere Methode dieser Konfiguration ist der Device Tree.

Logic Analyzer

Logic_Analyzer_kabel

Ein Logic Analyzer ist ein Osziloskop für mehrere Signale.
Die Signale selbst sind schlechter aufgelöst, dafür sieht man viele Signale.

Typischer weise sind die Signale digital; sie werden über einen Schwellwert  zu logisch ‚1‘ oder logische ‚0‘.

logic_analyzer_kanale

c++ Operator overloding

Kapitel 9: Operatoren nicht nur für Integers
(Übung Buchhandlung mit Christian: == für den Vergleich der Klasse Buch)

class Book {
private:
    string ISBN;
    string title;
    string author;
public: 
    Book(string isbn, string t, string a){ 
        ISBN = isbn; 
        title = t; 
        author = a; 
}

// buch1 == buch2

bool operator==(const Book& b2)       // new Datatyp is Book
  {
    if(ISBN == b2.ISBN)               // this new Typ is addresd by b2
      return true;
    else
      return false;
  }
Book buch1 = Book{978-8-123-12345-6, "Andorra", "Frisch"};
Book buch3 = Book{978-8-123-12345-6, "Mein Name ist Gantenbein", "Frisch"};
if (buch1 == buch3)
    cout << "Die Bücher sind gleich." << endl;
  else
    cout << "Die Bücher sind nicht gleich." << endl;

Hier sind buch1 und buch3 gleich, weil sie die gleichen ISBN haben.

 

Kapitel 10: IO
Der Operator << ist ursprünglich nur für String.
Sollen bei << auch andere Datentypen übergeben werden können, braucht es ein Overloading.

ostream& operator <<(ostream& os, const Date& d)

Ab sofort kann auch die Klasse Date dem stream übergeben werden.

 

 

 

 

..

C++: stream

– alle Daten werden zu chars
– In:
bedeutet von aussen zur CPU.
– out:
bedeutet von OS nach aussen
————————————————————————————-

istream

char Daten werden übergeben

ostream
sendet chars an eine Ort (file, konsole, speicher, ..)

ifstream  [Daten in File ablegen]
– Datei als String mitgeben
ifstream stream_a {„input.txt“}
– Inhalt wortweise in String ablegen string temp
– Strings in Vektor speichern   vector <string> input

while (stream_a >> temp) {      
        // fill vector
        input.push_back(temp);
    }


ofstream
[ lesen von einem file (wird als stream gemacht)]

cout << "Name of output file"
string name_outputfile;
cin >> name_outputfile;

ostream stream_1 {name_outputfile};
if (! stream_1) error("Konnte nicht eingelesen werden.");

 

strukturiert einlesen

struct Inputdata {
    int hour;
    double temperature; 
};
cout << "Please enter input file name: ";
    string name_inputfile;
    cin >> name_inputfile;
    ifstream ist {name_inputfile};
    if (!ist) throw ios_base::failure("can't open input file "+name_inputfile);
vector<Inputdata> temps; // structured vector
    int hour;
    double temperature;

    // read structured in
    while (ist >> hour >> temperature) {
        if (hour < 0 || 23 <hour) throw range_error("hour out of range");
        // fill vector
        temps.push_back(Inputdata{hour,temperature});
    }

 

strucktruriert ausgeben

// set brackets for clearer structure
    for (int i=0; i<input.size(); ++i)
        ost << '(' << input[i].hour << ','
            << input[i].temperature << ")\n";

 

 

 

 

vhdl: array aus struct

Array aus struct

  • token structure:
    cmd | 4 x midi_data (note + velocity) |  numb_notes
  • aus den Token wird ein Array gebildet
token_array()
.    token_line_1
.           command
.           midi_data
.                  note
.                  velocity
.            token_number
.     token_line_2
  1. Midi-Data Struktur bilden
-- define midi_data
type t_midi_data is record
            note : std_logic_vector(7 downto 0);
            velocity : std_logic_vector(7 downto 0);
        end record;

-- initialise (if needed)
variable data_1: t_midi_data;

2. Array für Midi-Data (weil es 4 x vorkommt)

-- define
type t_midi_data_array is array (3 downto 0) of t_midi_data;

-- initalise (if needed)
signal data_array: t_midi_data_array;

3. Ganze Token Struktur zusammensetzen

-- define
type t_token is record
      token_cmd : string(1 to 5);
      token_midi_data : t_midi_data_array;
       token_number : std_logic_vector(3 downto 0);
end record;

-- initialize (if needed)
signal token_linie: t_token;

4. Mehrere Token zu einem Array zusammenfassen

CONSTANT NUMBR_INPUTLINES: natural := 8;

-- define
type t_token_array is array( NUMBR_INPUTLINES-1 downto 0)  of t_token;

-- initialise
signal token_array_input: t_token_array;

 

Grundsätzlich braucht es keine Signale, da die Inputs direkt in input-array eingelesen werden und Zuweisungen direkt vom Array an das entsprechende Signal gegeben wird.
Einziges Signal das es braucht ist über das Gesamt-Array, damit es angesprochen werden kann.

————————————————————————————-

Werte zuweisen

t_token_array()
.    token_line_1
.           command
.           midi_data
.                  note
.                  velocity
.            token_number
.     token_line_2

-- initialisation
signal s_input_array: t_token_array;
s_token_line_1 <= s_input_array(0);

s_token_command <= s_input_array(0).command;

s_token_note_1 <= s_input_array(0).midi_data(1).note;
s_tk_velocity_1 <= s_input_array(0).m_data(1).vlcty;
s_token_note_2 <= s_input_array(0).midi_data(2).note;
s_tk_velocity_2 <= s_input_array(0).m_data(2).vlcty;

s_token_number <= s_input_array(0);

 

Die einzelnen Variablen werden mit dem Namen angesprochen.

 

 

VHDL Simulation: Wait statements

Neben den Assert statements (Vergleiche) basiert die Simulation vor allem auf den richtigen Pausen.

Warten bis…
–  Zustand eintrifft   WAIT UNTIL (s_midi = „1011);  wait until (clk = ‚1‘)
.  sehr wichtig für Koordination unter parallelen Prozessen.
–  Signal wechselt     wait on s_enable_datat;
–  Eines der Signale wechselt  wait on s_note_1, s_note_2, s_note_3;
.                 (nicht 100% sicher, ob nur 1 Signale oder alle)
–  Eine gewisse Zeit verstrichen ist wait for 10 us  wait for 1 * CLK_HALFPERIOD
–  Unbestimmt wait;  Hilft Simulation bei internen timing.
.   (Falls ein parameter noch nicht frei ist, wird gewartet.)
.   Ist z. B. sinnvoll nach read(file) ;

waits dürfen nur in processen eingebaut werden

Einfluss auf den Programmfluss
–  Wait-Statements sind sequentiell und stoppen den laufenden Prozess für diese Zeit
–  Stoppt der Prozess, werden die davor zugewiesenen Signale zugewiesen
– Ein wait aktualisert auch den Zeitstempel. Ohne waits in einem Process, kann nie die abgelaufene Zeit zum Simulieren übergeben (und das Programm beendet) werden. Der Prozess hängt in einem endlos loop.
– Ein (unbestimmtes) wait am Ende eines loop regelt selbständig, wie lang das Programm warten kann, bis wieder oben begonnen werden kann. (So entfiel z.B. die Fehlermeldung: „Can’t open file. Already used.“ Sobal die Datei wieder frei war, machte die Simulation weiter.