diff --git a/20211122/hp-musterloesung-20211122.tex b/20211122/hp-musterloesung-20211122.tex
index 7e8d77398c4ef19de65c13e1152f7934a81bce85..79548c0840546ceb221d17afd20bdc20df806635 100644
--- a/20211122/hp-musterloesung-20211122.tex
+++ b/20211122/hp-musterloesung-20211122.tex
@@ -1,4 +1,4 @@
-% hp-musterloesung-20211115.pdf - Solutions to the Exercises on Low-Level Programming
+% hp-musterloesung-20211122.pdf - Solutions to the Exercises on Low-Level Programming
 % Copyright (C) 2013, 2015, 2016, 2017, 2018, 2019, 2020, 2021  Peter Gerwinski
 %
 % This document is free software: you can redistribute it and/or
@@ -20,7 +20,7 @@
 % Attribution-ShareAlike 3.0 Unported License along with this
 % document.  If not, see <http://creativecommons.org/licenses/>.
 
-% README: Ausgabe von Hexadezimalzahlen, Einfügen in Strings, LED-Blinkmuster
+% README: Ausgabe von Hexadezimalzahlen, Länge von Strings, LED-Blinkmuster
 
 \documentclass[a4paper]{article}
 
diff --git a/20211122/hp-uebung-20211122.tex b/20211122/hp-uebung-20211122.tex
index 6e031dd149fdd13f3f11954d86f618491c988053..1f87ecffd4b8cf49807f1c8bfd1cfd9db4739ece 100644
--- a/20211122/hp-uebung-20211122.tex
+++ b/20211122/hp-uebung-20211122.tex
@@ -20,7 +20,7 @@
 % Attribution-ShareAlike 3.0 Unported License along with this
 % document.  If not, see <http://creativecommons.org/licenses/>.
 
-% README: Ausgabe von Hexadezimalzahlen, Einfügen in Strings, LED-Blinkmuster
+% README: Ausgabe von Hexadezimalzahlen, Länge von Strings, LED-Blinkmuster
 
 \documentclass[a4paper]{article}
 
diff --git a/20211129/aufgabe-1.c b/20211129/aufgabe-1.c
new file mode 100644
index 0000000000000000000000000000000000000000..2afae773ac2d564771ab6dfb473eed664070d3e2
--- /dev/null
+++ b/20211129/aufgabe-1.c
@@ -0,0 +1,10 @@
+#include <stdio.h>
+#include <stdint.h>
+
+int main (void)
+{
+  uint64_t x = 4262939000843297096;
+  char *s = &x;
+  printf ("%s\n", s);
+  return 0;
+}
diff --git a/20211129/aufgabe-3.c b/20211129/aufgabe-3.c
new file mode 100644
index 0000000000000000000000000000000000000000..cb09b0e10aade5c202ed88fddcb2e52d700d9915
--- /dev/null
+++ b/20211129/aufgabe-3.c
@@ -0,0 +1,16 @@
+#include <stdio.h>
+#include <stdint.h>
+
+typedef struct
+{
+  uint32_t a;
+  uint64_t b;
+  uint8_t c;
+} three_numbers;
+
+int main (void)
+{
+  three_numbers xyz = { 1819042120, 2410670883059281007, 0 };
+  printf ("%s\n", &xyz);
+  return 0;
+}
diff --git a/20211129/hp-20211129.pdf b/20211129/hp-20211129.pdf
new file mode 100644
index 0000000000000000000000000000000000000000..a4d016daec3c32ed1fe1ecc7cd0c0fd09e3815c0
Binary files /dev/null and b/20211129/hp-20211129.pdf differ
diff --git a/20211129/hp-20211129.tex b/20211129/hp-20211129.tex
new file mode 100644
index 0000000000000000000000000000000000000000..88ee498f82e9a8c4a14d47dab3238dc8d7cbdd7c
--- /dev/null
+++ b/20211129/hp-20211129.tex
@@ -0,0 +1,1057 @@
+% hp-20211129.pdf - Lecture Slides on Low-Level Programming
+% Copyright (C) 2012, 2013, 2015, 2016, 2017, 2018, 2019, 2020, 2021  Peter Gerwinski
+%
+% This document is free software: you can redistribute it and/or
+% modify it either under the terms of the Creative Commons
+% Attribution-ShareAlike 3.0 License, or under the terms of the
+% GNU General Public License as published by the Free Software
+% Foundation, either version 3 of the License, or (at your option)
+% any later version.
+%
+% This document is distributed in the hope that it will be useful,
+% but WITHOUT ANY WARRANTY; without even the implied warranty of
+% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+% GNU General Public License for more details.
+%
+% You should have received a copy of the GNU General Public License
+% along with this document.  If not, see <http://www.gnu.org/licenses/>.
+%
+% You should have received a copy of the Creative Commons
+% Attribution-ShareAlike 3.0 Unported License along with this
+% document.  If not, see <http://creativecommons.org/licenses/>.
+
+% README: Binärdarstellung negativer Zahlen, Speicherausrichtung – Alignment
+
+\documentclass[10pt,t]{beamer}
+
+\usepackage{pgslides}
+\usepackage{pdftricks}
+\usepackage{tikz}
+
+\begin{psinputs}
+  \usepackage[utf8]{inputenc}
+  \usepackage[german]{babel}
+  \usepackage[T1]{fontenc}
+  \usepackage{helvet}
+  \renewcommand*\familydefault{\sfdefault}
+  \usepackage{pstricks,pst-grad}
+\end{psinputs}
+
+\title{Hardwarenahe Programmierung}
+\author{Prof.\ Dr.\ rer.\ nat.\ Peter Gerwinski}
+\date{29.\ November 2021}
+
+\begin{document}
+
+\maketitleframe
+
+\nosectionnonumber{\inserttitle}
+
+\begin{frame}
+
+  \shownosectionnonumber
+
+  \begin{itemize}
+    \item[\textbf{1}] \textbf{Einführung}
+      \hfill\makebox(0,0)[br]{\raisebox{2.25ex}{\url{https://gitlab.cvh-server.de/pgerwinski/hp.git}}}
+    \item[\textbf{2}] \textbf{Einführung in C}
+    \item[\textbf{3}] \textbf{Bibliotheken}
+    \item[\textbf{4}] \textbf{Hardwarenahe Programmierung}
+      \begin{itemize}
+        \item[4.1] Bit-Operationen
+        \item[4.2] I/O-Ports
+        \color{medgreen}
+        \item[4.3] Interrupts
+        \item[4.4] volatile-Variable
+        \color{orange}
+        \item[4.6] Byte-Reihenfolge -- Endianness
+        \color{red}
+        \item[4.7] Binärdarstellung negativer Zahlen
+        \item[4.8] Speicherausrichtung -- Alignment
+      \end{itemize}
+    \item[\textbf{5}] \textbf{Algorithmen}
+      \begin{itemize}
+        \color{red}
+        \item[5.1] Differentialgleichungen
+        \color{black}
+        \vspace*{-0.1cm}
+        \item[\dots]
+      \end{itemize}
+    \item[\textbf{\dots}]
+%    \item[\textbf{4}] \textbf{Hardwarenahe Programmierung}
+%    \item[\textbf{5}] \textbf{Algorithmen}
+%    \item[\textbf{6}] \textbf{Ergänzungen und Ausblicke}
+  \end{itemize}
+  \vspace*{-1cm}
+
+\end{frame}
+
+\setcounter{section}{3}
+\section{Hardwarenahe Programmierung}
+\subsection{Bit-Operationen}
+\subsubsection{Zahlensysteme}
+
+\begin{frame}[fragile]
+
+  \showsection
+  \vspace*{-\smallskipamount}
+  \showsubsection
+  \vspace*{-\medskipamount}
+  \showsubsubsection
+
+  \begin{tabular}{rlrl}
+    Basis & Name & Beispiel & Anwendung \\[\smallskipamount]
+      2 & Binärsystem & 1\,0000\,0011 & Bit-Operationen \\
+      8 & Oktalsystem & \lstinline,0403, & Dateizugriffsrechte (Unix) \\
+     10 & Dezimalsystem & \lstinline,259, & Alltag \\
+     16 & Hexadezimalsystem & \lstinline,0x103, & Bit-Operationen \\
+    256 & (keiner gebräuchlich) & 0.0.1.3 & IP-Adressen (IPv4)
+  \end{tabular}
+
+  \bigskip
+
+  \begin{itemize}
+    \item
+      Computer rechnen im Binärsystem.
+    \item
+      Für viele Anwendungen (z.\,B.\ I/O-Ports, Grafik, \dots) ist es notwendig,\\
+      Bits in Zahlen einzeln ansprechen zu können.
+  \end{itemize}
+
+\end{frame}
+
+\begin{frame}[fragile]
+
+  \showsubsubsection
+
+  \begin{tabular}{rlrlrc}
+    \qquad 000 & \bf 0 \hspace*{1.5cm} & 0000 & \bf 0 & \quad 1000 & \bf 8\\
+           001 & \bf 1                 & 0001 & \bf 1 &       1001 & \bf 9\\
+           010 & \bf 2                 & 0010 & \bf 2 &       1010 & \bf A\\
+           011 & \bf 3                 & 0011 & \bf 3 &       1011 & \bf B\\[\smallskipamount]
+           100 & \bf 4                 & 0100 & \bf 4 &       1100 & \bf C\\
+           101 & \bf 5                 & 0101 & \bf 5 &       1101 & \bf D\\
+           110 & \bf 6                 & 0110 & \bf 6 &       1110 & \bf E\\
+           111 & \bf 7                 & 0111 & \bf 7 &       1111 & \bf F\\
+  \end{tabular}
+
+  \medskip
+
+  \begin{itemize}
+    \item
+      Oktal- und Hexadezimalzahlen lassen sich ziffernweise\\
+      in Binär-Zahlen umrechnen.
+    \item
+      Hexadezimalzahlen sind eine Kurzschreibweise für Binärzahlen,\\
+      gruppiert zu jeweils 4 Bits.
+    \item
+      Oktalzahlen sind eine Kurzschreibweise für Binärzahlen,\\
+      gruppiert zu jeweils 3 Bits.
+    \item
+      Trotz Taschenrechner u.\,ä.\ lohnt es sich,\\
+      die o.\,a.\ Umrechnungstabelle \textbf{auswendig} zu kennen.
+  \end{itemize}
+
+\end{frame}
+
+\subsubsection{Bit-Operationen in C}
+
+\begin{frame}[fragile]
+
+  \showsubsubsection
+
+  \begin{tabular}{lll}
+    C-Operator     & Verknüpfung              & Anwendung                \\[\smallskipamount]
+    \lstinline,&,  & Und                      & Bits gezielt löschen     \\
+    \lstinline,|,  & Oder                     & Bits gezielt setzen      \\
+    \lstinline,^,  & Exklusiv-Oder            & Bits gezielt invertieren \\
+    \lstinline,~,  & Nicht                    & Alle Bits invertieren    \\[\smallskipamount]
+    \lstinline,<<, & Verschiebung nach links  & Maske generieren         \\
+    \lstinline,>>, & Verschiebung nach rechts & Bits isolieren
+  \end{tabular}
+
+  \bigskip
+
+  Numerierung der Bits: von rechts ab 0
+
+  \medskip
+
+  \begin{tabular}{ll}
+    Bit Nr.\ 3 auf 1 setzen: &
+    \lstinline,a |= 1 << 3;, \\
+    Bit Nr.\ 4 auf 0 setzen: &
+    \lstinline,a &= ~(1 << 4);, \\
+    Bit Nr.\ 0 invertieren: &
+    \lstinline,a ^= 1 << 0;,
+  \end{tabular}
+
+  \smallskip
+
+  ~~Abfrage, ob Bit Nr.\ 1 gesetzt ist:\quad
+  \lstinline{if (a & (1 << 1))}
+
+\end{frame}
+
+\begin{frame}[fragile]
+
+  \showsubsubsection
+
+  C-Datentypen für Bit-Operationen:
+  \smallskip\par
+  \lstinline{#include <stdint.h>}
+  \medskip\par
+  \begin{tabular}{lllll}
+                    & 8 Bit & 16 Bit & 32 Bit & 64 Bit \\
+    mit Vorzeichen  & \lstinline,int8_t,
+                    & \lstinline,int16_t,
+                    & \lstinline,int32_t,
+                    & \lstinline,int64_t, \\
+    ohne Vorzeichen & \lstinline,uint8_t,
+                    & \lstinline,uint16_t,
+                    & \lstinline,uint32_t,
+                    & \lstinline,uint64_t,
+  \end{tabular}
+
+  \bigskip
+  \bigskip
+
+  Ausgabe:
+  \smallskip\par
+  \begin{lstlisting}
+    #include <stdio.h>
+    #include <stdint.h>
+    #include <inttypes.h>
+    ...
+    uint64_t x = 42;
+    printf ("Die Antwort lautet: %" PRIu64 "\n", x);
+  \end{lstlisting}
+
+\end{frame}
+
+\subsection{I/O-Ports}
+
+\begin{frame}[fragile]
+
+%  \showsection
+  \showsubsection
+  \vspace*{-1.5\medskipamount}
+  {\large\textbf{\color{structure}5.3\quad Interrupts}}
+
+  \bigskip
+
+  Kommunikation mit externen Geräten
+
+  \bigskip
+
+  \begin{center}
+    \includegraphics{io-ports-and-interrupts.pdf}
+  \end{center}
+
+\end{frame}
+
+\begin{frame}[fragile]
+
+  \showsubsection
+
+  In Output-Port schreiben = Aktoren ansteuern
+
+  Beispiel: LED
+
+  \medskip
+
+  \begin{lstlisting}
+    #include <avr/io.h>
+    ...
+    DDRC = 0x70;
+    PORTC = 0x40;
+  \end{lstlisting}
+  \begin{picture}(0,0)
+    \put(3,0.67){\begin{minipage}{3cm}
+                \color{red}%
+                binär: 0111\,0000\\
+                binär: 0100\,0000
+              \end{minipage}}
+    \put(10,0.67){\makebox(0,0)[r]{\color{red}Herstellerspezifisch!}}
+  \end{picture}
+
+  \bigskip
+
+  \lstinline{DDR} = Data Direction Register\\
+  Bit = 1 für Output-Port\\
+  Bit = 0 für Input-Port
+
+  \bigskip
+
+  \emph{Details: siehe Datenblatt und Schaltplan}
+
+\end{frame}
+
+\begin{frame}[fragile]
+
+  \showsubsection
+
+  Aus Input-Port lesen = Sensoren abfragen
+
+  Beispiel: Taster
+
+  \medskip
+
+  \begin{lstlisting}
+    #include <avr/io.h>
+    ...
+    DDRC = 0xfd;
+    while ((PINC & 0x02) == 0)
+      ; /* just wait */
+  \end{lstlisting}
+  \begin{picture}(0,0)(-1.5,-0.42)
+    \put(3,0.67){\begin{minipage}{3cm}
+                \color{red}%
+                binär: 1111\,1101\\
+                binär: 0000\,0010
+              \end{minipage}}
+    \put(10,0.67){\makebox(0,0)[r]{\color{red}Herstellerspezifisch!}}
+  \end{picture}
+
+  \bigskip
+
+  \lstinline{DDR} = Data Direction Register\\
+  Bit = 1 für Output-Port\\
+  Bit = 0 für Input-Port
+
+  \bigskip
+
+  \emph{Details: siehe Datenblatt und Schaltplan}
+  
+  \bigskip
+
+  Praktikumsaufgabe: Druckknopfampel
+
+\end{frame}
+
+\subsection{Interrupts}
+
+\begin{frame}[fragile]
+
+  \showsubsection
+
+  Externes Gerät ruft (per Stromsignal) Unterprogramm auf
+
+  Zeiger hinterlegen: "`Interrupt-Vektor"'
+
+  Beispiel: eingebaute Uhr\hfill
+  \makebox(0,0)[tr]{%
+    \only<1->{\begin{minipage}[t]{4.7cm}
+        \vspace*{-0.3cm}%
+        statt Zählschleife (\lstinline{_delay_ms}):\\
+        Hauptprogramm kann\\
+        andere Dinge tun
+      \end{minipage}}%
+    }
+
+  \medskip
+
+  \begin{lstlisting}
+    #include <avr/interrupt.h>
+
+    ...
+
+
+    ISR (TIMER0B_COMP_vect)
+    {
+      PORTD ^= 0x40;
+    }
+  \end{lstlisting}
+  \begin{picture}(0,0)
+    \color{red}
+    \put(1.9,3.1){\makebox(0,0)[tr]{\tikz{\draw[-latex](0,0)--(-1.4,-1.0);}}}
+    \put(2.0,3.2){\makebox(0,0)[l]{"`Dies ist ein Interrupt-Handler."'}}
+    \put(2.3,2.6){\makebox(0,0)[tr]{\tikz{\draw[-latex](0,0)--(-0.6,-0.55);}}}
+    \put(2.4,2.6){\makebox(0,0)[l]{Interrupt-Vektor darauf zeigen lassen}}
+  \end{picture}
+
+  Initialisierung über spezielle Ports:
+  \lstinline{TCCR0B}, \lstinline{TIMSK0}
+
+  \bigskip
+
+  \emph{Details: siehe Datenblatt und Schaltplan}
+
+  \vspace*{-2.5cm}\hfill
+  {\color{red}Herstellerspezifisch!}%
+  \hspace*{1cm}
+
+\end{frame}
+
+\begin{frame}[fragile]
+
+  \showsubsection
+
+  Externes Gerät ruft (per Stromsignal) Unterprogramm auf
+
+  Zeiger hinterlegen: "`Interrupt-Vektor"'
+
+  Beispiel: Taster\hfill
+  \makebox(0,0)[tr]{%
+    \begin{minipage}[t]{4.7cm}
+      \vspace*{-0.3cm}%
+      statt \newterm{Busy Waiting\/}:\\
+      Hauptprogramm kann\\
+      andere Dinge tun
+    \end{minipage}}
+
+  \medskip
+
+  \begin{lstlisting}
+    #include <avr/interrupt.h>
+    ...
+
+    ISR (INT0_vect)
+    {
+      PORTD ^= 0x40;
+    }
+  \end{lstlisting}
+
+  \medskip
+
+  Initialisierung über spezielle Ports:
+  \lstinline{EICRA}, \lstinline{EIMSK}
+
+  \bigskip
+
+  \emph{Details: siehe Datenblatt und Schaltplan}
+
+  \vspace*{-2.5cm}\hfill
+  {\color{red}Herstellerspezifisch!}%
+  \hspace*{1cm}
+
+\end{frame}
+
+\subsection{volatile-Variable}
+
+\begin{frame}[fragile]
+
+  \showsubsection
+
+  Externes Gerät ruft (per Stromsignal) Unterprogramm auf
+
+  Zeiger hinterlegen: "`Interrupt-Vektor"'
+
+  Beispiel: Taster
+
+  \vspace*{-2.5pt}
+
+  \begin{minipage}[t]{5cm}
+    \begin{onlyenv}<1>
+      \begin{lstlisting}[gobble=8]
+        ¡#include <avr/interrupt.h>
+        ...
+
+        uint8_t key_pressed = 0;
+
+        ISR (INT0_vect)
+        {
+          key_pressed = 1;
+        }¿
+      \end{lstlisting}
+    \end{onlyenv}
+    \begin{onlyenv}<2>
+      \begin{lstlisting}[gobble=8]
+        ¡#include <avr/interrupt.h>
+        ...
+
+        volatile uint8_t key_pressed = 0;
+
+        ISR (INT0_vect)
+        {
+          key_pressed = 1;
+        }¿
+      \end{lstlisting}
+    \end{onlyenv}
+  \end{minipage}\hfill
+  \begin{minipage}[t]{6cm}
+    \begin{lstlisting}[gobble=6]
+      ¡int main (void)
+      {
+        ...
+
+        while (1)
+          {
+            while (!key_pressed)
+              ;  /* just wait */
+            PORTD ^= 0x40;
+            key_pressed = 0;
+          }
+        return 0;
+      }¿
+    \end{lstlisting}
+  \end{minipage}
+
+  \pause
+  \begin{picture}(0,0)
+    \color{red}
+    \put(10.3,4.0){\makebox(0,0)[b]{\begin{minipage}{6cm}
+        \begin{center}
+          \textbf{volatile}:\\
+          Speicherzugriff\\
+          nicht wegoptimieren
+        \end{center}
+      \end{minipage}}}
+    \put(10.3,3.95){\makebox(0,0)[tr]{\tikz{\draw[-latex](0,0)--(-0.5,-0.9);}}}
+  \end{picture}
+
+\end{frame}
+
+\iffalse
+
+\begin{frame}[fragile]
+
+  \showsubsection
+
+  Was ist eigentlich \lstinline{PORTD}?
+
+  \bigskip
+  \pause
+
+  \lstinline[style=cmd]{avr-gcc -Wall -Os -mmcu=atmega328p blink-3.c -E}
+
+  \bigskip
+  \pause
+  \lstinline{PORTD = 0x01;}\\
+  \textarrow\quad
+  \lstinline[style=terminal]{(*(volatile uint8_t *)((0x0B) + 0x20)) = 0x01;}\\
+  \pause
+  \begin{picture}(0,2)(0,-1.7)
+    \color{red}
+    \put(5.75,0.3){$\underbrace{\rule{2.95cm}{0pt}}_{\mbox{Zahl: \lstinline|0x2B|}}$}
+    \pause
+    \put(1.55,0.3){$\underbrace{\rule{4.0cm}{0pt}}_{\mbox{\shortstack[t]{Umwandlung in Zeiger\\
+      auf \lstinline|volatile uint8_t|}}}$}
+    \pause
+    \put(1.32,-1){\makebox(0,0)[b]{\tikz{\draw[-latex](0,0)--(0,1.3)}}}
+    \put(1.12,-1.1){\makebox(0,0)[tl]{Dereferenzierung des Zeigers}}
+  \end{picture}
+
+  \pause
+  \textarrow\quad
+  \lstinline|volatile uint8_t|-Variable an Speicheradresse \lstinline|0x2B|
+
+  \pause
+  \bigskip
+  \bigskip
+
+  \textarrow\quad
+  \lstinline|PORTA = PORTB = PORTC = PORTD = 0| ist eine schlechte Idee.
+
+\end{frame}
+
+\fi
+
+\subsection{Byte-Reihenfolge -- Endianness}
+\subsubsection{Konzept}
+
+\begin{frame}[fragile]
+
+  \showsubsection
+  \showsubsubsection
+
+  Eine Zahl geht über mehrere Speicherzellen.\\
+  Beispiel: 16-Bit-Zahl in 2 8-Bit-Speicherzellen
+
+  \smallskip
+
+  Welche Bits liegen wo?
+
+  \pause
+  \bigskip
+
+  $1027 = 1024 + 2 + 1 = 0000\,0100\,0000\,0011_2 = 0403_{16}$
+
+  \pause
+  \bigskip
+  Speicherzellen:
+
+  \medskip
+  \begin{tabular}{|c|c|l}\cline{1-2}
+    \raisebox{-0.25ex}{04} & \raisebox{-0.25ex}{03} & \strut Big-Endian "`großes Ende zuerst"' \\\cline{1-2}
+    \multicolumn{2}{c}{} & \pause für Menschen leichter lesbar \pause \\
+    \multicolumn{3}{c}{} \\[-5pt]\cline{1-2}
+    \raisebox{-0.25ex}{03} & \raisebox{-0.25ex}{04} & \strut Little-Endian "`kleines Ende zuerst"' \\\cline{1-2}
+    \multicolumn{2}{c}{} & \pause bei Additionen effizienter
+  \end{tabular}
+
+  \pause
+  \medskip
+  \textarrow\ Geschmackssache
+  \pause\\
+  \quad\textbf{\dots\ außer bei Datenaustausch!}
+
+%  \pause
+%  \bigskip
+%
+%  Aber: nicht verwechseln! \qquad $0304_{16} = 772$
+
+\end{frame}
+
+\begin{frame}
+
+  \showsubsection
+  \showsubsubsection
+
+  Eine Zahl geht über mehrere Speicherzellen.\\
+  Beispiel: 16-Bit-Zahl in 2 8-Bit-Speicherzellen
+
+  \smallskip
+
+  Welche Bits liegen wo?
+
+  \medskip
+
+  \textarrow\ Geschmackssache\\
+  \textbf{\dots\ außer bei Datenaustausch!}
+
+  \begin{itemize}
+    \item
+      Dateiformate
+    \item
+      Datenübertragung
+  \end{itemize}
+
+\end{frame}
+
+\subsubsection{Dateiformate}
+
+\begin{frame}
+
+  \showsubsection
+  \showsubsubsection
+
+  Audio-Formate: Reihenfolge der Bytes in 16- und 32-Bit-Zahlen
+  \begin{itemize}
+    \item
+      RIFF-WAVE-Dateien (\file{.wav}): Little-Endian
+    \item
+      Au-Dateien (\file{.au}): Big-Endian
+    \pause
+    \item
+      ältere AIFF-Dateien (\file{.aiff}): Big-Endian
+    \item
+      neuere AIFF-Dateien (\file{.aiff}): Little-Endian
+  \end{itemize}
+
+  \pause
+  \bigskip
+
+  Grafik-Formate: Reihenfolge der Bits in den Bytes
+  \begin{itemize}
+    \item
+      PBM-Dateien: Big-Endian\only<4->{, MSB first}
+    \item
+      XBM-Dateien: Little-Endian\only<4->{, LSB first}
+  \end{itemize}
+  \only<4->{MSB/LSB = most/least significant bit}
+
+\end{frame}
+
+\subsubsection{Datenübertragung}
+
+\begin{frame}
+
+  \showsubsection
+  \showsubsubsection
+
+  \begin{itemize}
+    \item
+      RS-232 (serielle Schnittstelle): LSB first
+    \item
+      I$^2$C: MSB first
+    \item
+      USB: beides
+    \pause
+    \medskip
+    \item
+      Ethernet: LSB first
+    \item
+      TCP/IP (Internet): Big-Endian
+  \end{itemize}
+
+\end{frame}
+
+\subsection{Binärdarstellung negativer Zahlen}
+
+\begin{frame}[fragile]
+
+  \showsubsection
+
+  Speicher ist begrenzt!\\
+  \textarrow\ feste Anzahl von Bits
+
+  \medskip
+
+  8-Bit-Zahlen ohne Vorzeichen: \lstinline{uint8_t}\\
+  \textarrow\ Zahlenwerte von \lstinline{0x00} bis \lstinline{0xff} = 0 bis 255\\
+  \pause
+  \textarrow\ 255 + 1 = 0
+
+  \pause
+  \medskip
+
+  8-Bit-Zahlen mit Vorzeichen: \lstinline{int8_t}\\
+  \lstinline{0xff} = 255 ist die "`natürliche"' Schreibweise für $-1$.\\
+  \pause
+  \textarrow\ Zweierkomplement
+
+  \pause
+  \medskip
+
+  Oberstes Bit = 1: negativ\\
+  Oberstes Bit = 0: positiv\\
+  \textarrow\ 127 + 1 = $-128$
+
+\end{frame}
+
+\begin{frame}[fragile]
+
+  \showsubsection
+
+  Speicher ist begrenzt!\\
+  \textarrow\ feste Anzahl von Bits
+
+  \medskip
+
+  16-Bit-Zahlen ohne Vorzeichen:
+  \lstinline{uint16_t}\hfill\lstinline{uint8_t}\\
+  \textarrow\ Zahlenwerte von \lstinline{0x0000} bis \lstinline{0xffff}
+  = 0 bis 65535\hfill 0 bis 255\\
+  \textarrow\ 65535 + 1 = 0\hfill 255 + 1 = 0
+
+  \medskip
+
+  16-Bit-Zahlen mit Vorzeichen:
+  \lstinline{int16_t}\hfill\lstinline{int8_t}\\
+  \lstinline{0xffff} = 66535 ist die "`natürliche"' Schreibweise für $-1$.\hfill
+  \lstinline{0xff} = 255 = $-1$\\
+  \textarrow\ Zweierkomplement
+
+  \medskip
+
+  Oberstes Bit = 1: negativ\\
+  Oberstes Bit = 0: positiv\\
+  \textarrow\ 32767 + 1 = $-32768$
+
+  \bigskip
+  Literatur: \url{http://xkcd.com/571/}
+
+\end{frame}
+
+\begin{frame}[fragile]
+
+  \showsubsection
+
+  Frage: \emph{Für welche Zahl steht der Speicherinhalt\,
+  \raisebox{2pt}{%
+    \tabcolsep0.25em
+    \begin{tabular}{|c|c|}\hline
+      \rule{0pt}{11pt}a3 & 90 \\\hline
+    \end{tabular}}
+  (hexadezimal)?}
+  
+  \pause
+  \smallskip
+  Antwort: \emph{Das kommt darauf an.} ;--)
+
+  \pause
+  \medskip
+  Little-Endian:
+
+  \smallskip
+
+  \begin{tabular}{lrl}
+    als \lstinline,int8_t,: & $-93$ & (nur erstes Byte)\\
+    als \lstinline,uint8_t,: & $163$ & (nur erstes Byte)\\
+    als \lstinline,int16_t,: & $-28509$\\
+    als \lstinline,uint16_t,: & $37027$\\
+    \lstinline,int32_t, oder größer: & $37027$
+      & (zusätzliche Bytes mit Nullen aufgefüllt)
+  \end{tabular}
+
+  \pause
+  \medskip
+  Big-Endian:
+
+  \smallskip
+
+  \begin{tabular}{lrl}
+    als \lstinline,int8_t,:   & $-93$ & (nur erstes Byte)\\
+    als \lstinline,uint8_t,:  & $163$ & (nur erstes Byte)\\
+    als \lstinline,int16_t,:  & $-23664$\\
+    als \lstinline,uint16_t,: & $41872$\\ als \lstinline,int32_t,:  & $-1550843904$ & (zusätzliche Bytes\\
+    als \lstinline,uint32_t,: & $2744123392$  & mit Nullen aufgefüllt)\\
+    als \lstinline,int64_t,:  & $-6660823848880963584$\\
+    als \lstinline,uint64_t,: & $11785920224828588032$\\
+  \end{tabular}
+
+  \vspace*{-1cm}
+
+\end{frame}
+
+\subsection{Speicherausrichtung -- Alignment}
+
+\begin{frame}[fragile]
+
+  \showsubsection
+
+  \begin{lstlisting}
+    #include <stdint.h>
+
+    uint8_t a;
+    uint16_t b;
+    uint8_t c;
+  \end{lstlisting}
+
+  \pause
+  \bigskip
+
+  Speicheradresse durch 2 teilbar -- "`16-Bit-Alignment"'
+  \begin{itemize}
+    \item
+      2-Byte-Operation: effizienter
+    \pause
+    \item
+      \dots\ oder sogar nur dann erlaubt
+    \pause
+    \arrowitem
+      Compiler optimiert Speicherausrichtung
+  \end{itemize}
+
+  \medskip
+
+  \pause
+  \begin{minipage}{3cm}
+    \begin{lstlisting}[gobble=6]
+      ¡uint8_t a;
+      uint8_t dummy;
+      uint16_t b;
+      uint8_t c;¿
+    \end{lstlisting}
+  \end{minipage}
+  \pause
+  \begin{minipage}{3cm}
+    \begin{lstlisting}[gobble=6]
+      ¡uint8_t a;
+      uint8_t c;
+      uint16_t b;¿
+    \end{lstlisting}
+  \end{minipage}
+
+  \pause
+  \vspace{-1.75cm}
+  \strut\hfill
+  \begin{minipage}{6.5cm}
+    Fazit:
+    \begin{itemize}
+      \item
+        \textbf{Adressen von Variablen\\
+        sind systemabhängig}
+      \item
+        Bei Definition von Datenformaten\\
+        Alignment beachten \textarrow\ effizienter
+    \end{itemize}
+  \end{minipage}
+
+\end{frame}
+
+\section{Algorithmen}
+\subsection{Differentialgleichungen}
+
+\begin{frame}[fragile]
+
+  \showsection
+  \showsubsection
+
+  \textbf{Beispiel 1: Gleichmäßig beschleunigte Bewegung}
+
+  \strut\hfill
+  \begin{minipage}{2.5cm}
+    \vspace*{0.6cm}
+    \begin{align*}
+      x'(t) &= v_x(t) \\[0.65cm]
+      y'(t) &= v_y(t) \\[0.75cm]
+      v_x'(t) &= 0 \\[0.65cm]
+      v_y'(t) &= -g
+    \end{align*}
+    \vspace*{0.0cm}
+  \end{minipage}%
+  \only<1>{\hspace*{9.49cm}}\strut
+  \only<2->{\hfill$\Rightarrow$\hfill}%
+  \begin{onlyenv}<2-8>
+    \begin{minipage}{8.3cm}
+      \begin{align*}
+        x(t) &= \int v_x(t)\,dt
+          \visible<4->{= \int v_{0x}\,dt}
+          \visible<5->{= x_0 + v_{0x}\cdot t}\\[\medskipamount]
+        y(t) &= \int v_y(t)\,dt
+          \visible<7->{= \int v_{0y} - g\cdot t\,dt}
+          \visible<8->{= y_0 + v_{0y}\cdot t
+                         - {\textstyle\frac12}gt^2}\\[\bigskipamount]
+        v_x(t) &= \int 0\,dt
+          \visible<3->{= v_{0x}} \\[\medskipamount]
+        v_y(t) &= \int -g\,dt
+          \visible<6->{= v_{0y} - g\cdot t}
+      \end{align*}
+    \end{minipage}%
+  \end{onlyenv}%
+  \begin{onlyenv}<9->
+    \begin{minipage}{3.5cm}
+      \vspace*{0.5cm}
+      \begin{lstlisting}[gobble=8,xleftmargin=0.5em]
+        ¡x += vx * dt;¿
+      \end{lstlisting}
+      \vspace{0.75cm}
+      \begin{lstlisting}[gobble=8,xleftmargin=0.5em]
+        ¡y += vy * dt;¿
+      \end{lstlisting}
+      \vspace{0.90cm}
+      \begin{lstlisting}[gobble=8,xleftmargin=0.5em]
+        ¡vx += 0 * dt;¿
+      \end{lstlisting}
+      \vspace{0.75cm}
+      \begin{lstlisting}[gobble=8,xleftmargin=0.5em]
+        ¡vy += -g * dt;¿
+      \end{lstlisting}
+    \end{minipage}%
+    \begin{minipage}{5.13cm}
+      Siehe: \file{gtk-13.c}
+    \end{minipage}
+  \end{onlyenv}%
+  \hfill\strut
+
+\end{frame}
+
+\begin{frame}[fragile]
+  \showsection
+  \showsubsection
+
+  \textbf{Beispiel 1: Gleichmäßig beschleunigte Bewegung}
+
+  \medskip
+
+  \textbf{Beispiel 2: Mathematisches Pendel}
+
+  \vspace*{-2\bigskipamount}
+
+  \begin{picture}(0,0)
+    \put(8,-6.5){\includegraphics{pendulum.pdf}}
+  \end{picture}
+
+  \begin{eqnarray*}
+    \varphi'(t) &=& \omega(t) \\[\smallskipamount]
+    \omega'(t) &=& -\frac{g}{l}\cdot\sin\varphi(t)\hspace*{7.1cm}
+  \end{eqnarray*}
+  \vspace*{-1.5\medskipamount}
+  \begin{itemize}
+    \item
+      Von Hand (analytisch):\\
+      Lösung raten (Ansatz), Parameter berechnen
+    \item
+      Mit Computer (numerisch):\\
+      Eulersches Polygonzugverfahren
+  \end{itemize}
+  \smallskip
+  \begin{lstlisting}[gobble=0]
+    phi += dt * omega;
+    omega += - dt * g / l * sin (phi);
+  \end{lstlisting}
+
+  \pause
+  \bigskip
+
+  \textbf{Beispiel 3: Weltraum-Simulation}
+
+  Praktikumsaufgabe
+  \vspace*{-1cm}
+
+\end{frame}
+
+\nosectionnonumber{\inserttitle}
+
+\begin{frame}
+
+  \shownosectionnonumber
+
+  \begin{itemize}
+    \item[\textbf{1}] \textbf{Einführung}
+      \hfill\makebox(0,0)[br]{\raisebox{2.25ex}{\url{https://gitlab.cvh-server.de/pgerwinski/hp.git}}}
+    \item[\textbf{2}] \textbf{Einführung in C}
+    \item[\textbf{3}] \textbf{Bibliotheken}
+      \begin{itemize}
+        \item[3.1] Der Präprozessor
+        \item[3.2] Bibliotheken einbinden
+        \item[3.3] Bibliotheken verwenden
+        \color{medgreen}
+        \item[3.4] Projekt organisieren: make
+      \end{itemize}
+    \item[\textbf{4}] \textbf{Hardwarenahe Programmierung}
+      \begin{itemize}
+        \color{red}
+        \item[4.1] Bit-Operationen
+        \item[4.2] I/O-Ports
+        \item[4.3] Interrupts
+        \vspace*{-0.1cm}
+        \item[\dots]
+      \end{itemize}
+    \item[\textbf{5}] \textbf{Algorithmen}
+      \begin{itemize}
+        \color{medgreen}
+        \item[5.1] Differentialgleichungen
+        \color{black}
+        \vspace*{-0.1cm}
+        \item[\dots]
+      \end{itemize}
+    \item[\textbf{\dots}]
+%    \item[\textbf{4}] \textbf{Hardwarenahe Programmierung}
+%    \item[\textbf{5}] \textbf{Algorithmen}
+%    \item[\textbf{6}] \textbf{Ergänzungen und Ausblicke}
+  \end{itemize}
+  \vspace*{-1cm}
+
+\end{frame}
+
+\nosectionnonumber{\inserttitle}
+
+\begin{frame}
+
+  \shownosectionnonumber
+
+  \begin{itemize}
+    \item[\textbf{1}] \textbf{Einführung}
+      \hfill\makebox(0,0)[br]{\raisebox{2.25ex}{\url{https://gitlab.cvh-server.de/pgerwinski/hp.git}}}
+    \item[\textbf{2}] \textbf{Einführung in C}
+    \item[\textbf{3}] \textbf{Bibliotheken}
+    \item[\textbf{4}] \textbf{Hardwarenahe Programmierung}
+      \begin{itemize}
+        \item[4.1] Bit-Operationen
+        \item[4.2] I/O-Ports
+        \item[4.3] Interrupts
+        \item[4.4] volatile-Variable
+        \color{medgreen}
+        \item[4.6] Byte-Reihenfolge -- Endianness
+        \item[4.7] Binärdarstellung negativer Zahlen
+        \item[4.8] Speicherausrichtung -- Alignment
+      \end{itemize}
+    \item[\textbf{5}] \textbf{Algorithmen}
+      \begin{itemize}
+        \color{medgreen}
+        \item[5.1] Differentialgleichungen
+        \color{black}
+        \vspace*{-0.1cm}
+        \item[\dots]
+      \end{itemize}
+    \item[\textbf{\dots}]
+%    \item[\textbf{4}] \textbf{Hardwarenahe Programmierung}
+%    \item[\textbf{5}] \textbf{Algorithmen}
+%    \item[\textbf{6}] \textbf{Ergänzungen und Ausblicke}
+  \end{itemize}
+
+\end{frame}
+
+\end{document}
diff --git a/20211129/hp-2021ws-p3.pdf b/20211129/hp-2021ws-p3.pdf
new file mode 100644
index 0000000000000000000000000000000000000000..cc20aac76609abda47a89ad4c722bd7c29405af0
Binary files /dev/null and b/20211129/hp-2021ws-p3.pdf differ
diff --git a/20211129/hp-2021ws-p3.tex b/20211129/hp-2021ws-p3.tex
new file mode 100644
index 0000000000000000000000000000000000000000..45a58ee1a664c36b85596b6d9f08dff349cfd2d3
--- /dev/null
+++ b/20211129/hp-2021ws-p3.tex
@@ -0,0 +1,201 @@
+% hp-2021ws-p3.pdf - Labor Notes on Low-Level Programming
+% Copyright (C) 2014, 2015, 2018, 2019, 2020, 2021  Peter Gerwinski
+%
+% This document is free software: you can redistribute it and/or
+% modify it either under the terms of the Creative Commons
+% Attribution-ShareAlike 3.0 License, or under the terms of the
+% GNU General Public License as published by the Free Software
+% Foundation, either version 3 of the License, or (at your option)
+% any later version.
+%
+% This document is distributed in the hope that it will be useful,
+% but WITHOUT ANY WARRANTY; without even the implied warranty of
+% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+% GNU General Public License for more details.
+%
+% You should have received a copy of the GNU General Public License
+% along with this document.  If not, see <http://www.gnu.org/licenses/>.
+%
+% You should have received a copy of the Creative Commons
+% Attribution-ShareAlike 3.0 Unported License along with this
+% document.  If not, see <http://creativecommons.org/licenses/>.
+
+% README: Versuch 3: Weltraum-Simulation
+
+\documentclass[a4paper]{article}
+
+\usepackage{pgscript}
+\usepackage{multicol}
+%\usepackage{sfmath}
+
+\sloppy
+\raggedcolumns
+\pagestyle{empty}
+\addtolength{\textheight}{1cm}
+\newcommand{\sep}{~$\cdot$~}
+\newcommand{\mylicense}{CC BY-SA (Version 4.0) oder GNU GPL (Version 3 oder höher)}
+
+\begin{document}
+
+  \makebox(0,0.005)[tl]{\includegraphics[scale=0.72]{logo-hochschule-bochum-cvh-text-v2.pdf}}\hfill
+  \makebox(0,0)[tr]{\includegraphics[scale=0.5]{logo-hochschule-bochum.pdf}}
+  \par\bigskip\bigskip
+  \begin{center}
+    \Large\textbf{Praktikumsversuch 3: Weltraum-Simulation}
+    \par\medskip
+    \normalsize Hardwarenahe Programmierung\sep
+    Wintersemester 2021/22\sep
+    Prof.~Dr.~Peter Gerwinski
+  \end{center}
+
+  Aufgabe: Schreiben Sie ein C-Programm,
+  das die Bahnen von beliebig vielen Massenpunkten unter Einfluß der Gravitation
+  simuliert und in bewegter Grafik darstellt.
+
+  \begin{multicols}{2}
+
+    \begin{itemize}
+      \item
+        Zwei Massenpunkte ("`Himmelskörper"') mit den Massen $m_i$ und $m_j$
+        an den Orten $\vec{r}_i$ und $\vec{r}_j$ ziehen einander an.
+        Diese Kraft heißt Gravitation. Sie hat den Betrag:
+        \begin{equation}
+          |\vec{F}_{ij}| = \frac{m_j\cdot m_i\cdot G}{|\vec{r}_j - \vec{r}_i|^2}
+        \end{equation}
+        Hierbei ist $G$ eine Konstante (Gravitationskonstante).
+
+      \item
+        Die auf einen Himmelskörper wirkende Gesamtkraft $\vec{F}_i$
+        ergibt sich als Summe der von allen anderen Himmelskörpern herrührenden
+        Gravitationskräfte:
+        \begin{equation}
+          \vec{F}_i = \sum_{j=0,\,j\ne i}^{N - 1} \vec{F}_{ij}
+        \end{equation}
+
+      \item
+        Die Gravitationskraft beschleunigt jeden Himmelskörper gemäß:
+        \begin{equation}
+          \vec{F_i} = m_i\cdot \vec{a_i}
+        \end{equation}
+
+      \item
+        Beispiel: Wir betrachten zwei Himmelskörper. Einer davon ("`Zentralgestirn"')
+        ruht im Zentrum ($\vec{r}_0 = 0$, $\vec{v}_0 = 0$)
+        und hat eine wesentlich größere Masse als der andere
+        ("`Satellit"', $m_1 \ll m_0$).  Mit geeignetem Anfangsort $\vec{r}_1$
+        und geeigneter Anfangsgeschwindigkeit $\vec{v}_1$ beschreibt dann
+        der Satellit eine elliptische Umlaufbahn um das Zentralgestirn.
+
+      \item
+        Wir rechnen in zwei Dimensionen $x$ und $y$.
+
+      \item
+        Für die Zerlegung einer Kraft $\vec{F}_{ij}$ in $x$- und $y$-Komponenten
+        benötigen Sie nur die Grundrechenarten und die Wurzelfunktion,
+        jedoch insbesondere \emph{keine} trigonometrischen Funktionen:
+        \begin{equation}
+          \vec{F}_{ij} = |\vec{F}_{ij}| \cdot \frac{\vec{r}_j - \vec{r}_i}{|\vec{r}_j - \vec{r}_i|}
+        \end{equation}
+
+      \item
+        Die Wurzelfunktion \lstinline{sqrt()} finden Sie
+        in der Mathematik-Bibliothek.
+        Um diese zu nutzen, verwenden Sie \lstinline{#include <math.h>} im Quelltext,
+        und geben Sie beim \lstinline[style=cmd]{gcc}-Aufruf
+        \lstinline[style=cmd]{-lm} mit an.
+
+      \columnbreak
+
+      \item
+        Für die Simulation betrachten wir das System in kurzen Zeitintervallen $dt$
+        und berechnen die Änderungen des Ortes $\vec{r}_i = (x_i,y_i)$
+        und der Geschwindigkeit $\vec{v}_i = (v_{xi},v_{yi})$ jedes Himmelskörpers
+        mit Hilfe des expliziten Eulerschen Polygonzugverfahrens.
+        \par
+        (Wer möchte, darf natürlich auch andere Verfahren anwenden,
+        beispielsweise das klassische Runge-Kutta-Verfahren 4.~Ordnung.)
+
+      \item
+        Für eine derartige Simulation
+        einschließlich ihrer Darstellung als bewegte Grafik
+        können Sie sich von dem Beispiel-Programm \gitfile{hp}{2020ws/20201217}{gtk-16.c}
+        inspirieren lassen.
+%        (Compilieren mit:
+%        \lstinline[style=cmd]{gcc}
+%        \lstinline[style=cmd]{-Wall}
+%        \lstinline[style=cmd]{-O}
+%        \lstinline[style=cmd]{gtk-16.c}
+%        \lstinline[style=cmd]{$(pkg-config}
+%        \lstinline[style=cmd]{--cflags}
+%        \lstinline[style=cmd]{--libs}
+%        \lstinline[style=cmd]{gtk+-3.0)}
+%        \lstinline[style=cmd]{-o}
+%        \lstinline[style=cmd]{gtk-16})
+
+      \item
+        In einer \file{GTK+}-\lstinline{drawing_area}
+        liegt der Nullpunkt der Zeichnung oben links,
+        eine Längeneinheit entspricht einem Pixel,
+        und die $y$-Koordinate wächst nach unten.
+        Es empfiehlt sich, die Koordinaten so umzurechnen,
+        daß der Nullpunkt in der Mitte der Zeichnung liegt,
+        die Längeneinheit Ihrem persönlichen Geschmack entspricht
+        und die $y$-Koordinate nach oben wächst.
+
+      \item
+        Beispiel-Szenarien für 3 oder mehr Körper:
+        \vspace{-\smallskipamount}
+        \begin{itemize}\itemsep0pt
+          \item 
+            Planet mit Mond umkreist Sonne
+          \item
+            Sonne mit mehreren Planeten, die sich gegenseitig beeinflussen
+          \item
+            zwei Sonnen umkreisen sich gegenseitig, Planet kreist drumherum
+          \item
+            Raumsonde besucht nacheinander mehrere Planeten
+        \end{itemize}
+
+      \item
+        \textbf{Hinweis:}
+        Speichern Sie die verschiedenen Körper nicht als separate Variable,
+        sondern in einem Array. Ihr Programm wird dadurch nicht nur flexibler,
+        sondern auch übersichtlicher und weniger fehleranfällig.
+
+      \item
+        \textbf{Online-Abgabe:}
+        Ihre Quelltexte mit den Lösungen der Praktikumsaufgabe schicken Sie bitte
+        per E-Mail an \file{peter.gerwinski@hs-bochum.de}
+        mit dem \textbf{Betreff:} \lstinline[style=terminal]{Poo6va2U}
+        unter Angabe von Name, Matrikel-Nummer,
+        Studiengang (MI/MP/TI) und Studienmodell (KIA/KIS/GS).
+
+    \end{itemize}
+
+  \end{multicols}
+
+  \vspace*{-\bigskipamount}
+
+  \strut\hfill\emph{Viel Erfolg!}\qquad\qquad
+
+  \vfill
+
+  \begingroup
+
+    \small
+
+    \setlength{\leftskip}{3cm}
+
+    Stand: 29.\ November 2021
+
+%    Soweit nicht anders angegeben:\\
+    Copyright \copyright\ 2014, 2015, 2018, 2019, 2020, 2021\quad Peter Gerwinski\\
+    Lizenz: \mylicense
+
+    Sie können diese Praktikumsunterlagen einschließlich \LaTeX-Quelltext
+    und Beispielprogramm herunterladen unter:
+    \url{https://gitlab.cvh-server.de/pgerwinski/hp}
+
+  \endgroup
+
+\end{document}
diff --git a/20211129/hp-musterloesung-20211129.pdf b/20211129/hp-musterloesung-20211129.pdf
new file mode 100644
index 0000000000000000000000000000000000000000..82f8ec915be7e743cd26fbfb963d4fb12f86796f
Binary files /dev/null and b/20211129/hp-musterloesung-20211129.pdf differ
diff --git a/20211129/hp-musterloesung-20211129.tex b/20211129/hp-musterloesung-20211129.tex
new file mode 100644
index 0000000000000000000000000000000000000000..a9e66d107cbaac3fe1f7ed336581eb7623ea650f
--- /dev/null
+++ b/20211129/hp-musterloesung-20211129.tex
@@ -0,0 +1,484 @@
+% hp-musterloesung-20211129.pdf - Solutions to the Exercises on Low-Level Programming
+% Copyright (C) 2013, 2015, 2016, 2017, 2018, 2019, 2020, 2021  Peter Gerwinski
+%
+% This document is free software: you can redistribute it and/or
+% modify it either under the terms of the Creative Commons
+% Attribution-ShareAlike 3.0 License, or under the terms of the
+% GNU General Public License as published by the Free Software
+% Foundation, either version 3 of the License, or (at your option)
+% any later version.
+%
+% This document is distributed in the hope that it will be useful,
+% but WITHOUT ANY WARRANTY; without even the implied warranty of
+% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+% GNU General Public License for more details.
+%
+% You should have received a copy of the GNU General Public License
+% along with this document.  If not, see <http://www.gnu.org/licenses/>.
+%
+% You should have received a copy of the Creative Commons
+% Attribution-ShareAlike 3.0 Unported License along with this
+% document.  If not, see <http://creativecommons.org/licenses/>.
+
+% README: Trickprogrammierung, Thermometer-Baustein an I²C-Bus
+
+\documentclass[a4paper]{article}
+
+\usepackage{pgscript}
+\usepackage{gensymb}
+
+\newcommand{\ItwoC}{I\raisebox{0.5ex}{\footnotesize 2}C}
+\newcommand{\ITWOC}{I\raisebox{0.5ex}{\normalsize 2}C}
+
+\begin{document}
+
+  \section*{Hardwarenahe Programmierung\\
+            Musterlösung zu den Übungsaufgaben -- 29.\ November 2021}
+
+  \exercise{Trickprogrammierung}
+
+  Wir betrachten das folgende Programm (Datei: \gitfile{hp}{2021ws/20211129}{aufgabe-1.c}):
+  \begin{lstlisting}
+    #include <stdio.h>
+    #include <stdint.h>
+
+    int main (void)
+    {
+      uint64_t x = 4262939000843297096;
+      char *s = &x;
+      printf ("%s\n", s);
+      return 0;
+    }
+  \end{lstlisting}
+  Das Programm wird compiliert und auf einem 64-Bit-Little-Endian-Computer ausgeführt:
+  \begin{lstlisting}[style=terminal]
+    $ ¡gcc -Wall -O aufgabe-1.c -o aufgabe-1¿
+    aufgabe-1.c: In function `main':
+    aufgabe-1.c:7:13: warning: initialization from incompatible pointer type [...]
+    $ ¡./aufgabe-1¿
+    Hallo
+  \end{lstlisting}
+
+  \begin{itemize}
+    \item[(a)]
+      Erklären Sie die Warnung beim Compilieren. \points{2}
+    \item[(b)]
+      Erklären Sie die Ausgabe des Programms. \points{5}
+    \item[(c)]
+      Wie würde die Ausgabe des Programms auf einem 64-Bit-Big-Endian-Computer lauten? \points{3}
+  \end{itemize}
+  Hinweis: Modifizieren Sie das Programm
+  und lassen Sie sich Speicherinhalte ausgeben.
+
+  \solution
+
+  \begin{itemize}
+    \item[(a)]
+      \textbf{Erklären Sie die Warnung beim Compilieren.}
+
+      Zeile 7 des Programms enthält eine Zuweisung von \lstinline{&x}
+      an die Variable \lstinline{s}.
+      Der Ausdruck \lstinline{&x} steht für die Speicheradresse der Variablen \lstinline{x},
+      ist also ein Zeiger auf \lstinline{x},
+      also ein Zeiger auf eine \lstinline{uint64_t}.
+      Die Variable \lstinline{s} hingegen ist ein Zeiger auf \lstinline{char},
+      also ein Zeiger auf eine viel kleinere Zahl,
+      also ein anderer Zeigertyp.
+
+    \item[(b)]
+      \textbf{Erklären Sie die Ausgabe des Programms.}
+
+      Die 64-Bit-Zahl (\lstinline{uint64_t}) \lstinline{x}
+      belegt 8 Speicherzellen (Bytes) von jeweils 8 Bit.
+      Um herauszufinden, was diese enthalten,
+      lassen wir uns \lstinline{x} als Hexadezimalzahl ausgeben,
+      z.\,B.\ mittels \lstinline{printf ("%lx\n", x)}
+      (auf 32-Bit-Rechnern: \lstinline{"%llx\n"})
+      oder mittels \lstinline{printf ("%" PRIx64 "\n", x)}
+      (erfordert \lstinline{#include <inttypes.h>}
+      -- siehe die Datei \gitfile{hp}{2021ws/20211129}{loesung-1-1.c}).
+      Das Ergebnis lautet:
+      \begin{lstlisting}[style=terminal,gobble=8]
+        3b29006f6c6c6148
+      \end{lstlisting}
+      Auf einzelne Bytes verteilt:
+      \begin{lstlisting}[style=terminal,gobble=8]
+        3b 29 00 6f 6c 6c 61 48
+      \end{lstlisting}
+      Auf einem Little-Endian-Rechner
+      ist die Reihenfolge der Bytes in den Speicherzellen genau umgekehrt:
+      \begin{lstlisting}[style=terminal,gobble=8]
+        48 61 6c 6c 6f 00 29 3b
+      \end{lstlisting}
+      Wenn wir uns diese Bytes als Zeichen ausgeben lassen
+      (\lstinline{printf()} mit \lstinline{%c} -- siehe die Datei \gitfile{hp}{2021ws/20211129}{loesung-1-2.c}),
+      erhalten wir:
+      \begin{lstlisting}[style=terminal,gobble=8]
+        H a l l o  ) ;
+      \end{lstlisting}
+      Das Zeichen hinter "`Hallo"' ist ein Null-Symbol (Zahlenwert 0)
+      und wird von \lstinline{printf ("%s")} als Ende des Strings erkannt.
+      Damit ist die Ausgabe \lstinline[style=terminal]{Hallo}
+      des Programms erklärt.
+
+    \goodbreak
+    \item[(c)]
+      \textbf{Wie würde die Ausgabe des Programms auf einem 64-Bit-Big-Endian-Computer lauten?}
+
+      Auf einem Big-Endian-Computer (egal, wieviele Bits die Prozessorregister haben)
+      ist die Reihenfolge der Bytes in den Speicherzellen genau umgekehrt
+      wie auf einem Little-Endian-Computer, hier also:
+      \begin{lstlisting}[style=terminal,gobble=8]
+        3b 29 00 6f 6c 6c 61 48
+      \end{lstlisting}
+      \lstinline{printf ("%s")} gibt in diesem Fall die Hexadezimalzahlen
+      \lstinline[style=terminal]{3b} und \lstinline[style=terminal]{29}
+      als Zeichen aus. Danach steht das String-Ende-Symbol mit Zahlenwert 0,
+      und die Ausgabe bricht ab.
+      Da, wie oben ermittelt, die Hexadezimalzahl \lstinline[style=terminal]{3b}
+      für das Zeichen \lstinline[style=terminal]{;}
+      und \lstinline[style=terminal]{29}
+      für das Zeichen \lstinline[style=terminal]{)} steht,
+      lautet somit die Ausgabe:
+      \begin{lstlisting}[style=terminal,gobble=8]
+        ;)
+      \end{lstlisting}
+      Um die Aufgabe zu lösen, können Sie übrigens auch
+      auf einem Little-Endian-Computer (Standard-Notebook)
+      einen Big-Endian-Computer simulieren,
+      indem Sie die Reihenfolge der Bytes in der Zahl \lstinline{x} umdrehen
+      -- siehe die Datei \gitfile{hp}{2021ws/20211129}{loesung-1-3.c}.
+  \end{itemize}
+
+  \exercise{Thermometer-Baustein an \ITWOC-Bus}
+
+  Eine Firma stellt einen elektronischen Thermometer-Baustein her,
+  den man über die serielle Schnittstelle (RS-232) an einen PC anschließen kann,
+  um die Temperatur auszulesen.
+  Nun wird eine Variante des Thermo"-meter-Bausteins entwickelt,
+  die die Temperatur zusätzlich über einen \ItwoC-Bus bereitstellt.
+
+  Um das neue Thermometer zu testen, wird es in ein Gefäß mit heißem Wasser gelegt,
+  das langsam auf Zimmertemperatur abkühlt.
+  Alle 10 Minuten liest ein Programm, das auf dem PC läuft,
+  die gemessene Temperatur über beide Schnittstellen aus
+  und erzeugt daraus die folgende Tabelle:
+
+  \begin{center}
+    \renewcommand{\arraystretch}{1.2}
+    \begin{tabular}{|c|c|c|}\hline
+      Zeit /\,min. & Temperatur per RS-232 /\,\degree C & Temperatur per \ItwoC\ /\,\degree C \\\hline\hline
+      \phantom{0}0 & 94 & 122 \\\hline
+      10 & 47 & 244 \\\hline
+      20 & 30 & 120 \\\hline
+      30 & 24 & \phantom{0}24 \\\hline
+      40 & 21 & 168 \\\hline
+    \end{tabular}
+  \end{center}
+
+  \begin{itemize}
+    \item[(a)]
+      Aus dem Vergleich der Meßdaten läßt sich
+      auf einen Fehler bei der \ItwoC-Übertragung schließen.\\
+      Um welchen Fehler handelt es sich,
+      und wie ergibt sich dies aus den Meßdaten?
+      \points{5}
+    \item[(b)]
+      Schreiben Sie eine C-Funktion \lstinline{uint8_t repair (uint8_t data)},
+      die eine über den \ItwoC-Bus empfangene fehlerhafte Temperatur \lstinline{data} korrigiert.
+      \points{5}
+  \end{itemize}
+
+  \solution
+
+  \begin{itemize}
+    \item[(a)]
+      \textbf{Aus dem Vergleich der Meßdaten läßt sich
+      auf einen Fehler bei der \ItwoC-Übertragung schließen.
+      Um welchen Fehler handelt es sich,
+      und wie ergibt sich dies aus den Meßdaten?}
+
+      Sowohl RS-232 als auch \ItwoC\ übertragen die Daten Bit für Bit.
+      Für die Fehlersuche ist es daher sinnvoll,
+      die Meßwerte als Binärzahlen zu betrachten:
+
+      \begin{center}
+        \renewcommand{\arraystretch}{1.2}
+        \begin{tabular}{|c|c|c|}\hline
+          Zeit /\,min. & Temperatur per RS-232 /\,\degree C & Temperatur per \ItwoC\ /\,\degree C \\\hline\hline
+          \phantom{0}0 & 94$_{10}$ = 01011110$_2$ & 122$_{10}$           = 01111010$_2$ \\\hline
+          10           & 47$_{10}$ = 00101111$_2$ & 244$_{10}$           = 11110100$_2$ \\\hline
+          20           & 30$_{10}$ = 00011110$_2$ & 120$_{10}$           = 01111000$_2$ \\\hline
+          30           & 24$_{10}$ = 00011000$_2$ & \phantom{0}24$_{10}$ = 00011000$_2$ \\\hline
+          40           & 21$_{10}$ = 00010101$_2$ & 168$_{10}$           = 10101000$_2$ \\\hline
+        \end{tabular}
+      \end{center}
+
+      Man erkennt, daß die Reihenfolge der Bits in den (fehlerhaften) \ItwoC-Meßwerten
+      genau die umgekehrte Reihenfolge der Bits in den (korrekten) RS-232-Mewßwerten ist.
+      Der Übertragungsfehler besteht also darin,
+      daß die Bits in der falschen Reihenfolge übertragen wurden.
+
+      Dies paßt gut damit zusammen,
+      daß die Bit-Reihenfolge von \ItwoC\ \emph{MSB First}, die von RS-232 hingegen \emph{LSB First\/} ist.
+      Offenbar haben die Entwickler der \ItwoC-Schnittstelle dies übersehen
+      und die \ItwoC-Daten ebenfalls \emph{LSB First\/} übertragen.
+
+    \goodbreak
+    \item[(b)]
+      \textbf{Schreiben Sie eine C-Funktion \lstinline{uint8_t repair (uint8_t data)},
+      die eine über den \ItwoC-Bus empfangene fehlerhafte Temperatur \lstinline{data} korrigiert.}
+
+      Die Aufgabe der Funktion besteht darin,
+      eine 8-Bit-Zahl \lstinline{data} entgegenzunehmen,
+      die Reihenfolge der 8 Bits genau umzudrehen
+      und das Ergebnis mittels \lstinline{return} zurückzugeben.
+
+      Zu diesem Zweck gehen wir die 8 Bits in einer Schleife durch
+      -- siehe die Datei \gitfile{hp}{2021ws/20211129}{loesung-2.c}.
+      Wir lassen eine Lese-Maske \lstinline{mask_data} von rechts nach links
+      und gleichzeitig eine Schreib-Maske \lstinline{mask_result}
+      von links nach rechts wandern.
+      Immer wenn die Lese-Maske in \lstinline{data} eine 1 findet,
+      schreibt die Schreib-Maske diese in die Ergebnisvariable \lstinline{result}.
+
+      Da \lstinline{result} auf 0 initialisiert wurde,
+      brauchen wir Nullen nicht hineinzuschreiben.
+      Ansonsten wäre dies mit \lstinline{result &= ~mask_result} möglich.
+
+      Um die Schleife bis 8 zählen zu lassen,
+      könnte man eine weitere Zähler-Variable von 0 bis 7 zählen lassen,
+      z.\,B.\ \lstinline{for (int i = 0; i < 8; i++)}.
+      Dies ist jedoch nicht nötig, wenn man beachtet,
+      daß die Masken den Wert 0 annehmen,
+      sobald das Bit aus der 8-Bit-Variablen herausgeschoben wurde.
+      In \gitfile{hp}{2021ws/20211129}{loesung-2.c} wird \lstinline{mask_data} auf 0 geprüft;
+      genausogut könnte man auch \lstinline{mask_result} prüfen.
+
+      Das \lstinline{return result} ist notwendig.
+      Eine Ausgabe des Ergebnisses per \lstinline{printf()} o.\,ä.\
+      erfüllt \emph{nicht\/} die Aufgabenstellung.
+      (In \gitfile{hp}{2021ws/20211129}{loesung-2.c} erfolgt entsprechend \lstinline{printf()}
+      nur im Testprogramm \lstinline{main()}.)
+  \end{itemize}
+
+  \exercise{Speicherformate von Zahlen}
+
+  Wir betrachten das folgende Programm (\gitfile{hp}{2021ws/20211129}{aufgabe-3.c}):
+  \begin{lstlisting}
+    #include <stdio.h>
+    #include <stdint.h>
+
+    typedef struct
+    {
+      uint32_t a;
+      uint64_t b;
+      uint8_t c;
+    } three_numbers;
+
+    int main (void)
+    {
+      three_numbers xyz = { 1819042120, 2410670883059281007, 0 };
+      printf ("%s\n", &xyz);
+      return 0;
+    }
+  \end{lstlisting}
+
+  Das Programm wird für einen 32-Bit-Rechner compiliert und ausgeführt.\\
+  (Die \lstinline[style=cmd]{gcc}-Option \lstinline[style=cmd]{-m32} sorgt dafür,
+  daß \lstinline[style=cmd]{gcc} Code für einen 32-Bit-Prozessor erzeugt.)
+
+  \begin{lstlisting}[style=terminal]
+    $ ¡gcc -Wall -m32 aufgabe-2.c -o aufgabe-2¿
+    aufgabe-2.c: In function "main":
+    aufgabe-2.c:14:13: warning: format "%s" expects argument of type "char *", but
+    argument 2 has type "three_numbers * {aka struct <anonymous> *}" [-Wformat=]
+       printf ("%s\n", &xyz);
+                 ^
+    $ ¡./aufgabe-2¿
+    Hallo, Welt!
+  \end{lstlisting}
+
+  \begin{enumerate}[\quad(a)]
+    \item
+      Erklären Sie die beim Compilieren auftretende Warnung.
+      \points{2}
+    \item
+      Erklären Sie die Ausgabe des Programms.
+      \points{4}
+    \item
+      Welche Endianness hat der verwendete Rechner?
+      Wie sähe die Ausgabe auf einem Rechner mit entgegengesetzter Endianness aus?
+      \points{2}
+    \item
+      Dasselbe Programm wird nun für einen 64-Bit-Rechner compiliert und ausgeführt.\\
+      (Die \lstinline[style=cmd]{gcc}-Option \lstinline[style=cmd]{-m64} sorgt dafür,
+      daß \lstinline[style=cmd]{gcc} Code für einen 64-Bit-Prozessor erzeugt.)
+      \begin{lstlisting}[style=terminal,gobble=8]
+        $ ¡gcc -Wall -m64 aufgabe-2.c -o aufgabe-2¿
+        aufgabe-2.c: In function "main":
+        aufgabe-2.c:14:13: warning: format "%s" expects argument of type "char *",
+        but argument 2 has type "three_numbers * {aka struct <anonymous> *}"
+        [-Wformat=]
+           printf ("%s\n", &xyz);
+                     ^
+        $ ¡./aufgabe-2¿
+        Hall5V
+      \end{lstlisting}
+      (Es ist möglich, daß die konkrete Ausgabe auf Ihrem Rechner anders aussieht.)\par
+      Erklären Sie die geänderte Ausgabe des Programms.
+      \points{3}
+  \end{enumerate}
+
+  \solution
+
+  \begin{enumerate}[\quad(a)]
+    \item
+      \textbf{Erklären Sie die beim Compilieren auftretende Warnung.}
+
+      Die Funktion \lstinline{printf()} mit der Formatspezifikation \lstinline{%s}
+      erwartet als Parameter einen String, d.\,h.\ einen Zeiger auf \lstinline{char}.
+      Die Adresse (\lstinline{&}) der Variablen \lstinline{xyz}
+      ist zwar ein Zeiger, aber nicht auf \lstinline{char},
+      sondern auf einen \lstinline{struct} vom Typ \lstinline{three_numbers}.
+      Eine implizite Umwandlung des Zeigertyps ist zwar möglich,
+      aber normalerweise nicht das, was man beabsichtigt.
+
+    \item
+      \textbf{Erklären Sie die Ausgabe des Programms.}
+
+      Ein String in C ist ein Array von \lstinline{char}s
+      bzw.\ ein Zeiger auf \lstinline{char}.
+      Da die Funktion \lstinline{printf()} mit der Formatspezifikation \lstinline{%s}
+      einen String erwartet, wird sie das, worauf der übergebene Zeiger zeigt,
+      als ein Array von \lstinline{char}s interpretieren.
+      Ein \lstinline{char} entspricht einer 8-Bit-Speicherzelle.
+      Um die Ausgabe des Programms zu erklären, müssen wir daher
+      die Speicherung der Zahlen in den einzelnen 8-Bit-Speicherzellen betrachten.
+
+      Hierfür wandeln wir zunächst die Zahlen von Dezimal nach Hexadezimal um.
+      Sofern nötig (hier nicht der Fall) füllen wir von links mit Nullen auf,
+      um den gesamten von der Variablen belegten Speicherplatz zu füllen
+      (hier: 32 Bit, 64 Bit, 8 Bit).
+      Jeweils 2 Hex-Ziffern stehen für 8 Bit.
+      \begin{center}
+        \begin{tabular}{rcl}
+          dezimal & & hexadezimal \\[\smallskipamount]
+          1\,819\,042\,120 & = & 6C\,6C\,61\,48 \\
+          2\,410\,670\,883\,059\,281\,007 & = & 21\,74\,6C\,65\,57\,20\,2C\,6F \\
+          0 & = & 00
+        \end{tabular}
+      \end{center}
+      Die Anordnung dieser 8-Bit-Zellen im Speicher lautet
+      \textbf{auf einem Big-Endian-Rechner} wie folgt:
+      \begin{center}
+        \begin{tabular}{|c|c|c|c|c|c|c|c|c|c|c|c|c|}\hline
+          \raisebox{0.5ex}{\strut}
+            6C & 6C & 61 & 48 &
+            21 & 74 & 6C & 65 & 57 & 20 & 2C & 6F &
+            00
+          \\\hline
+        \end{tabular}\\[-4.2ex]
+        \kern1.7em%
+        $\underbrace{\rule{9.8em}{0pt}}_{\mbox{\lstinline{a}}}$\kern1pt%
+        $\underbrace{\rule{18.8em}{0pt}}_{\mbox{\lstinline{b}}}$\kern1pt%
+        $\underbrace{\rule{2.2em}{0pt}}_{\mbox{\lstinline{c}}}$%
+      \end{center}
+      \textbf{Auf einem Little-Endian-Rechner} lautet sie hingegen:
+      \begin{center}
+        \begin{tabular}{|c|c|c|c|c|c|c|c|c|c|c|c|c|}\hline
+%          \raisebox{0.5ex}{\strut}
+%            H & a & l & l &
+%            o & , &   & W & e & l & t & ! &  \\\hline
+          \raisebox{0.5ex}{\strut}
+            48 & 61 & 6C & 6C &
+            6F & 2C & 20 & 57 & 65 & 6C & 74 & 21 &
+            00
+          \\\hline
+        \end{tabular}\\[-4.2ex]
+        \kern1.7em%
+        $\underbrace{\rule{9.8em}{0pt}}_{\mbox{\lstinline{a}}}$\kern1pt%
+        $\underbrace{\rule{18.8em}{0pt}}_{\mbox{\lstinline{b}}}$\kern1pt%
+        $\underbrace{\rule{2.2em}{0pt}}_{\mbox{\lstinline{c}}}$%
+      \end{center}
+      Anhand einer ASCII-Tabelle erkennt man,
+      daß die Big-Endian-Variante dem String \lstinline{"llaH!tleW ,o"}
+      und die Little-Endian-Variante dem String \lstinline{"Hallo, Welt!"}
+      entspricht -- jeweils mit einem Null-Symbol am Ende,
+      das von der Variablen \lstinline{c} herrührt.
+
+      Auf einem Little-Endian-Rechner wird daher
+      \lstinline[style=terminal]{Hallo, Welt!} ausgegeben.
+
+    \item
+      \textbf{Welche Endianness hat der verwendete Rechner?}
+
+      Little-Endian (Begründung siehe oben)
+
+      \textbf{Wie sähe die Ausgabe auf einem Rechner mit entgegengesetzter Endianness aus?}
+
+      \lstinline[style=terminal]{llaH!tleW ,o} (Begründung siehe oben)
+
+    \item
+      \textbf{Dasselbe Programm wird nun für einen 64-Bit-Rechner compiliert und ausgeführt.\\
+      (Die \lstinline[style=cmd]{gcc}-Option \lstinline[style=cmd]{-m64} sorgt dafür,
+      daß \lstinline[style=cmd]{gcc} Code für einen 64-Bit-Prozessor erzeugt.)}
+      \begin{lstlisting}[style=terminal,gobble=8]
+        $ ¡gcc -Wall -m64 aufgabe-2.c -o aufgabe-2¿
+        aufgabe-2.c: In function "main":
+        aufgabe-2.c:14:13: warning: format "%s" expects argument of type "char *",
+        but argument 2 has type "three_numbers * {aka struct <anonymous> *}"
+        [-Wformat=]
+           printf ("%s\n", &xyz);
+                     ^
+        $ ¡./aufgabe-2¿
+        Hall5V
+      \end{lstlisting}
+      \textbf{(Es ist möglich, daß die konkrete Ausgabe auf Ihrem Rechner anders aussieht.)}\par
+      \textbf{Erklären Sie die geänderte Ausgabe des Programms.}
+
+      \goodbreak
+
+      Auf einem 64-Bit-Rechner hat eine 64-Bit-Variable
+      ein \textbf{64-Bit-Alignment},
+      d.\,h.\ ihre Speicheradresse muß durch 8 teilbar sein.
+
+      Der Compiler legt die Variablen daher wie folgt im Speicher ab (Little-Endian):
+      \begin{center}
+        \begin{tabular}{|c|c|c|c|c|c|c|c|c|c|c|c|c|c|c|c|c|}\hline
+          \raisebox{0.5ex}{\strut}
+            48 & 61 & 6C & 6C & ?? & ?? & ?? & ?? &
+            6F & 2C & 20 & 57 & 65 & 6C & 74 & 21 &
+            00
+          \\\hline
+        \end{tabular}\\[-4.2ex]
+        \kern1.7em%
+        $\underbrace{\rule{9.8em}{0pt}}_{\mbox{\lstinline{a}}}$\kern1pt%
+        $\underbrace{\rule{9.1em}{0pt}}_{\mbox{Füll-Bytes}}$\kern1pt%
+        $\underbrace{\rule{18.8em}{0pt}}_{\mbox{\lstinline{b}}}$\kern1pt%
+        $\underbrace{\rule{2.2em}{0pt}}_{\mbox{\lstinline{c}}}$%
+      \end{center}
+      Der Inhalt der Füll-Bytes ist undefiniert.
+      Im Beispiel aus der Aufgabenstellung entsteht hier die Ausgabe
+      \lstinline[style=terminal]{5V}, was den (zufälligen) hexadezimalen Werten
+      35 56 entspricht:
+      \begin{center}
+        \begin{tabular}{|c|c|c|c|c|c|c|c|c|c|c|c|c|c|c|c|c|}\hline
+          \raisebox{0.5ex}{\strut}
+            48 & 61 & 6C & 6C & 35 & 56 & 00 & ?? &
+            6F & 2C & 20 & 57 & 65 & 6C & 74 & 21 &
+            00
+          \\\hline
+        \end{tabular}\\[-4.2ex]
+        \kern1.7em%
+        $\underbrace{\rule{9.8em}{0pt}}_{\mbox{\lstinline{a}}}$\kern1pt%
+        $\underbrace{\rule{9.1em}{0pt}}_{\mbox{Füll-Bytes}}$\kern1pt%
+        $\underbrace{\rule{18.8em}{0pt}}_{\mbox{\lstinline{b}}}$\kern1pt%
+        $\underbrace{\rule{2.2em}{0pt}}_{\mbox{\lstinline{c}}}$%
+      \end{center}
+      Da danach die Ausgabe aufhört, muß an der nächsten Stelle
+      ein Null-Symbol stehen, das das Ende des Strings anzeigt.
+      Der Inhalt der darauf folgenden Speicherzelle bleibt unbekannt.
+  \end{enumerate}
+
+\end{document}
diff --git a/20211129/hp-uebung-20211129.pdf b/20211129/hp-uebung-20211129.pdf
new file mode 100644
index 0000000000000000000000000000000000000000..b88e4a195ecefd36fe9bf24f73f0f1e8828a5fa7
Binary files /dev/null and b/20211129/hp-uebung-20211129.pdf differ
diff --git a/20211129/hp-uebung-20211129.tex b/20211129/hp-uebung-20211129.tex
new file mode 100644
index 0000000000000000000000000000000000000000..687eb8f6b544b1bf4cb01eff3558376b4d6d008f
--- /dev/null
+++ b/20211129/hp-uebung-20211129.tex
@@ -0,0 +1,195 @@
+% hp-uebung-20211122.pdf - Exercises on Low-Level Programming
+% Copyright (C) 2013, 2015, 2016, 2017, 2018, 2019, 2020, 2021  Peter Gerwinski
+%
+% This document is free software: you can redistribute it and/or
+% modify it either under the terms of the Creative Commons
+% Attribution-ShareAlike 3.0 License, or under the terms of the
+% GNU General Public License as published by the Free Software
+% Foundation, either version 3 of the License, or (at your option)
+% any later version.
+%
+% This document is distributed in the hope that it will be useful,
+% but WITHOUT ANY WARRANTY; without even the implied warranty of
+% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+% GNU General Public License for more details.
+%
+% You should have received a copy of the GNU General Public License
+% along with this document.  If not, see <http://www.gnu.org/licenses/>.
+%
+% You should have received a copy of the Creative Commons
+% Attribution-ShareAlike 3.0 Unported License along with this
+% document.  If not, see <http://creativecommons.org/licenses/>.
+
+% README: Trickprogrammierung, Thermometer-Baustein an I²C-Bus
+
+\documentclass[a4paper]{article}
+
+\usepackage{pgscript}
+\usepackage{gensymb}
+
+\newcommand{\ItwoC}{I\raisebox{0.5ex}{\footnotesize 2}C}
+\newcommand{\ITWOC}{I\raisebox{0.5ex}{\normalsize 2}C}
+
+\begin{document}
+
+%  \thispagestyle{empty}
+
+  \section*{Hardwarenahe Programmierung\\
+            Übungsaufgaben -- 22.\ November 2021}
+
+  Diese Übung enthält Punkteangaben wie in einer Klausur.
+  Um zu "`bestehen"', müssen Sie innerhalb von 90 Minuten
+  unter Verwendung ausschließlich zugelassener Hilfsmittel
+  15 Punkte (von insgesamt \totalpoints) erreichen.
+
+  \exercise{Trickprogrammierung}
+
+  Wir betrachten das folgende Programm (Datei: \gitfile{hp}{2021ws/20211129}{aufgabe-1.c}):
+  \begin{lstlisting}
+    #include <stdio.h>
+    #include <stdint.h>
+
+    int main (void)
+    {
+      uint64_t x = 4262939000843297096;
+      char *s = &x;
+      printf ("%s\n", s);
+      return 0;
+    }
+  \end{lstlisting}
+  Das Programm wird compiliert und auf einem 64-Bit-Little-Endian-Computer ausgeführt:
+  \begin{lstlisting}[style=terminal]
+    $ ¡gcc -Wall -O aufgabe-1.c -o aufgabe-1¿
+    aufgabe-1.c: In function `main':
+    aufgabe-1.c:7:13: warning: initialization from incompatible pointer type [...]
+    $ ¡./aufgabe-1¿
+    Hallo
+  \end{lstlisting}
+
+  \begin{itemize}
+    \item[(a)]
+      Erklären Sie die Warnung beim Compilieren. \points{2}
+    \item[(b)]
+      Erklären Sie die Ausgabe des Programms. \points{5}
+    \item[(c)]
+      Wie würde die Ausgabe des Programms auf einem 64-Bit-Big-Endian-Computer lauten? \points{3}
+  \end{itemize}
+  Hinweis: Modifizieren Sie das Programm
+  und lassen Sie sich Speicherinhalte ausgeben.
+
+  \exercise{Thermometer-Baustein an \ITWOC-Bus}
+
+  Eine Firma stellt einen elektronischen Thermometer-Baustein her,
+  den man über die serielle Schnittstelle (RS-232) an einen PC anschließen kann,
+  um die Temperatur auszulesen.
+  Nun wird eine Variante des Thermo"-meter-Bausteins entwickelt,
+  die die Temperatur zusätzlich über einen \ItwoC-Bus bereitstellt.
+
+  Um das neue Thermometer zu testen, wird es in ein Gefäß mit heißem Wasser gelegt,
+  das langsam auf Zimmertemperatur abkühlt.
+  Alle 10 Minuten liest ein Programm, das auf dem PC läuft,
+  die gemessene Temperatur über beide Schnittstellen aus
+  und erzeugt daraus die folgende Tabelle:
+
+  \begin{center}
+    \renewcommand{\arraystretch}{1.2}
+    \begin{tabular}{|c|c|c|}\hline
+      Zeit /\,min. & Temperatur per RS-232 /\,\degree C & Temperatur per \ItwoC\ /\,\degree C \\\hline\hline
+      \phantom{0}0 & 94 & 122 \\\hline
+      10 & 47 & 244 \\\hline
+      20 & 30 & 120 \\\hline
+      30 & 24 & \phantom{0}24 \\\hline
+      40 & 21 & 168 \\\hline
+    \end{tabular}
+  \end{center}
+
+  \begin{itemize}
+    \item[(a)]
+      Aus dem Vergleich der Meßdaten läßt sich
+      auf einen Fehler bei der \ItwoC-Übertragung schließen.\\
+      Um welchen Fehler handelt es sich,
+      und wie ergibt sich dies aus den Meßdaten?
+      \points{5}
+    \item[(b)]
+      Schreiben Sie eine C-Funktion \lstinline{uint8_t repair (uint8_t data)},
+      die eine über den \ItwoC-Bus empfangene fehlerhafte Temperatur \lstinline{data} korrigiert.
+      \points{5}
+  \end{itemize}
+
+  \exercise{Speicherformate von Zahlen}
+
+  Wir betrachten das folgende Programm (\gitfile{hp}{2021ws/20211129}{aufgabe-3.c}):
+  \begin{lstlisting}
+    #include <stdio.h>
+    #include <stdint.h>
+
+    typedef struct
+    {
+      uint32_t a;
+      uint64_t b;
+      uint8_t c;
+    } three_numbers;
+
+    int main (void)
+    {
+      three_numbers xyz = { 1819042120, 2410670883059281007, 0 };
+      printf ("%s\n", &xyz);
+      return 0;
+    }
+  \end{lstlisting}
+
+  Das Programm wird für einen 32-Bit-Rechner compiliert und ausgeführt.\\
+  (Die \lstinline[style=cmd]{gcc}-Option \lstinline[style=cmd]{-m32} sorgt dafür,
+  daß \lstinline[style=cmd]{gcc} Code für einen 32-Bit-Prozessor erzeugt.)
+
+  \begin{lstlisting}[style=terminal]
+    $ ¡gcc -Wall -m32 aufgabe-2.c -o aufgabe-2¿
+    aufgabe-2.c: In function "main":
+    aufgabe-2.c:14:13: warning: format "%s" expects argument of type "char *", but
+    argument 2 has type "three_numbers * {aka struct <anonymous> *}" [-Wformat=]
+       printf ("%s\n", &xyz);
+                 ^
+    $ ¡./aufgabe-2¿
+    Hallo, Welt!
+  \end{lstlisting}
+
+  \begin{enumerate}[\quad(a)]
+    \item
+      Erklären Sie die beim Compilieren auftretende Warnung.
+      \points{2}
+    \item
+      Erklären Sie die Ausgabe des Programms.
+      \points{4}
+    \item
+      Welche Endianness hat der verwendete Rechner?
+      Wie sähe die Ausgabe auf einem Rechner mit entgegengesetzter Endianness aus?
+      \points{2}
+    \item
+      Dasselbe Programm wird nun für einen 64-Bit-Rechner compiliert und ausgeführt.\\
+      (Die \lstinline[style=cmd]{gcc}-Option \lstinline[style=cmd]{-m64} sorgt dafür,
+      daß \lstinline[style=cmd]{gcc} Code für einen 64-Bit-Prozessor erzeugt.)
+      \begin{lstlisting}[style=terminal,gobble=8]
+        $ ¡gcc -Wall -m64 aufgabe-2.c -o aufgabe-2¿
+        aufgabe-2.c: In function "main":
+        aufgabe-2.c:14:13: warning: format "%s" expects argument of type "char *",
+        but argument 2 has type "three_numbers * {aka struct <anonymous> *}"
+        [-Wformat=]
+           printf ("%s\n", &xyz);
+                     ^
+        $ ¡./aufgabe-2¿
+        Hall5V
+      \end{lstlisting}
+      (Es ist möglich, daß die konkrete Ausgabe auf Ihrem Rechner anders aussieht.)\par
+      Erklären Sie die geänderte Ausgabe des Programms.
+      \points{3}
+  \end{enumerate}
+
+  \begin{flushright}
+    \textit{Viel Erfolg!}
+  \end{flushright}
+
+  \makeatletter
+    \immediate\write\@mainaux{\string\gdef\string\totalpoints{\arabic{points}}}
+  \makeatother
+
+\end{document}
diff --git a/20211129/io-ports-and-interrupts.pdf b/20211129/io-ports-and-interrupts.pdf
new file mode 120000
index 0000000000000000000000000000000000000000..bcd46f7afb35605b20bdb05637e6de0a039893ec
--- /dev/null
+++ b/20211129/io-ports-and-interrupts.pdf
@@ -0,0 +1 @@
+../common/io-ports-and-interrupts.pdf
\ No newline at end of file
diff --git a/20211129/loesung-1-1.c b/20211129/loesung-1-1.c
new file mode 100644
index 0000000000000000000000000000000000000000..26fcc817796b3da118b5dda92f45bfb870e315b6
--- /dev/null
+++ b/20211129/loesung-1-1.c
@@ -0,0 +1,13 @@
+#include <stdio.h>
+#include <stdint.h>
+#include <inttypes.h>
+
+int main (void)
+{
+  uint64_t x = 4262939000843297096;
+  char *s = &x;
+  printf ("%lx\n", x);
+  printf ("%" PRIx64 "\n", x);
+  printf ("%s\n", s);
+  return 0;
+}
diff --git a/20211129/loesung-1-2.c b/20211129/loesung-1-2.c
new file mode 100644
index 0000000000000000000000000000000000000000..7151db69b2e675f17517d7b7c3814bbda3b1fa89
--- /dev/null
+++ b/20211129/loesung-1-2.c
@@ -0,0 +1,15 @@
+#include <stdio.h>
+#include <stdint.h>
+#include <inttypes.h>
+
+int main (void)
+{
+  uint64_t x = 4262939000843297096;
+  char *s = &x;
+  printf ("%lx\n", x);
+  printf ("%" PRIx64 "\n", x);
+  printf ("%c %c %c %c %c %c %c %c\n",
+          0x48, 0x61, 0x6c, 0x6c, 0x6f, 0x00, 0x29, 0x3b);
+  printf ("%s\n", s);
+  return 0;
+}
diff --git a/20211129/loesung-1-3.c b/20211129/loesung-1-3.c
new file mode 100644
index 0000000000000000000000000000000000000000..fadccdef1155e4d16b5da0c8a82d8e7ae76ca3cc
--- /dev/null
+++ b/20211129/loesung-1-3.c
@@ -0,0 +1,11 @@
+#include <stdio.h>
+#include <stdint.h>
+#include <inttypes.h>
+
+int main (void)
+{
+  uint64_t x = 0x48616c6c6f00293b;
+  char *s = &x;
+  printf ("%s\n", s);
+  return 0;
+}
diff --git a/20211129/loesung-2.c b/20211129/loesung-2.c
new file mode 100644
index 0000000000000000000000000000000000000000..b02d98b51b9bc525a567afea2f0dce5a8e6413a5
--- /dev/null
+++ b/20211129/loesung-2.c
@@ -0,0 +1,26 @@
+#include <stdio.h>
+#include <stdint.h>
+
+uint8_t repair (uint8_t data)
+{
+  uint8_t result = 0;
+  uint8_t mask_data = 0x01;
+  uint8_t mask_result = 0x80;
+  while (mask_data)
+    {
+      if (data & mask_data)
+        result |= mask_result;
+      mask_data <<= 1;
+      mask_result >>= 1;
+    }
+  return result;
+}
+
+int main (void)
+{
+  int data[] = { 122, 244, 120, 24, 168, -1 };
+  int i = 0;
+  while (data[i] >= 0)
+    printf ("%d\n", repair (data[i++]));
+  return 0;
+}
diff --git a/20211129/logo-hochschule-bochum-cvh-text-v2.pdf b/20211129/logo-hochschule-bochum-cvh-text-v2.pdf
new file mode 120000
index 0000000000000000000000000000000000000000..4aa99b8f81061aca6dcaf43eed2d9efef40555f8
--- /dev/null
+++ b/20211129/logo-hochschule-bochum-cvh-text-v2.pdf
@@ -0,0 +1 @@
+../common/logo-hochschule-bochum-cvh-text-v2.pdf
\ No newline at end of file
diff --git a/20211129/logo-hochschule-bochum.pdf b/20211129/logo-hochschule-bochum.pdf
new file mode 120000
index 0000000000000000000000000000000000000000..b6b9491e370e499c9276918182cdb82cb311bcd1
--- /dev/null
+++ b/20211129/logo-hochschule-bochum.pdf
@@ -0,0 +1 @@
+../common/logo-hochschule-bochum.pdf
\ No newline at end of file
diff --git a/20211129/pendulum-0.c b/20211129/pendulum-0.c
new file mode 100644
index 0000000000000000000000000000000000000000..6faebdc7ad779d89ab8e2eacd189240ace1fb406
--- /dev/null
+++ b/20211129/pendulum-0.c
@@ -0,0 +1,69 @@
+#include <gtk/gtk.h>
+#include <math.h>
+
+int width = 320;
+int height = 240;
+int gap = height / 20;
+int r = gap;
+double visual_length = height - 2 * gap - r;
+
+double phi0 = -0.5;
+double omega0 = 0.0;
+double t0 = 0.0;
+double g = 9.81;
+double l = 1.0;
+double dt = 0.02;
+
+double t = t0;
+double phi = phi0;
+double omega = omega0;
+
+gboolean draw (GtkWidget *widget, cairo_t *c, gpointer data)
+{
+  GdkRGBA blue = { 0.0, 0.5, 1.0, 1.0 };
+
+  int x = width / 2 + visual_length * sin (phi);
+  int y = gap + visual_length * cos (phi);
+
+  gdk_cairo_set_source_rgba (c, &blue);
+  cairo_move_to (c, width / 2, gap);
+  cairo_line_to (c, x, y);
+  cairo_stroke (c);
+  cairo_arc (c, x, y, r, 0, 2 * G_PI);
+  cairo_fill (c);
+
+  return FALSE;  /* TRUE to stop other handlers from being invoked for the event.
+                    FALSE to propagate the event further. */
+}
+
+gboolean timer (GtkWidget *widget)
+{
+  t += dt;
+  phi += omega * dt;
+  omega += - dt * g / l * sin (phi);
+
+  gtk_widget_queue_draw_area (widget, 0, 0, width, height);
+  g_timeout_add (50, (GSourceFunc) timer, widget);
+  return FALSE;
+}
+
+int main (int argc, char **argv)
+{
+  gtk_init (&argc, &argv);
+
+  GtkWidget *window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+  gtk_widget_show (window);
+  gtk_window_set_title (GTK_WINDOW (window), "Hello");
+  g_signal_connect (window, "destroy", G_CALLBACK (gtk_main_quit), NULL);
+
+  GtkWidget *drawing_area = gtk_drawing_area_new ();
+  gtk_widget_show (drawing_area);
+  gtk_container_add (GTK_CONTAINER (window), drawing_area);
+  gtk_widget_set_size_request (drawing_area, width, height);
+  g_signal_connect (drawing_area, "draw", G_CALLBACK (draw), NULL);
+
+  g_timeout_add (50, (GSourceFunc) timer, drawing_area);
+
+  gtk_main ();
+  return 0;
+}
diff --git a/20211129/pendulum-1.c b/20211129/pendulum-1.c
new file mode 100644
index 0000000000000000000000000000000000000000..44f4c4fde79d96ed604882b0d5ce22a9035e1400
--- /dev/null
+++ b/20211129/pendulum-1.c
@@ -0,0 +1,69 @@
+#include <gtk/gtk.h>
+#include <math.h>
+
+#define WIDTH 320
+#define HEIGHT 240
+#define GAP (HEIGHT / 20)
+#define r GAP
+#define visual_length (HEIGHT - 2 * GAP - r)
+
+#define phi0 (-0.5)
+#define omega0 0.0
+#define t0 0.0
+#define g 9.81
+#define l 1.0
+#define dt 0.02
+
+double t = t0;
+double phi = phi0;
+double omega = omega0;
+
+gboolean draw (GtkWidget *widget, cairo_t *c, gpointer data)
+{
+  GdkRGBA blue = { 0.0, 0.5, 1.0, 1.0 };
+
+  int x = WIDTH / 2 + visual_length * sin (phi);
+  int y = GAP + visual_length * cos (phi);
+
+  gdk_cairo_set_source_rgba (c, &blue);
+  cairo_move_to (c, WIDTH / 2, 10);
+  cairo_line_to (c, x, y);
+  cairo_stroke (c);
+  cairo_arc (c, x, y, r, 0, 2 * G_PI);
+  cairo_fill (c);
+
+  return FALSE;  /* TRUE to stop other handlers from being invoked for the event.
+                    FALSE to propagate the event further. */
+}
+
+gboolean timer (GtkWidget *widget)
+{
+  t += dt;
+  phi += omega * dt;
+  omega += - dt * g / l * sin (phi);
+
+  gtk_widget_queue_draw_area (widget, 0, 0, WIDTH, HEIGHT);
+  g_timeout_add (50, (GSourceFunc) timer, widget);
+  return FALSE;
+}
+
+int main (int argc, char **argv)
+{
+  gtk_init (&argc, &argv);
+
+  GtkWidget *window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+  gtk_widget_show (window);
+  gtk_window_set_title (GTK_WINDOW (window), "Hello");
+  g_signal_connect (window, "destroy", G_CALLBACK (gtk_main_quit), NULL);
+
+  GtkWidget *drawing_area = gtk_drawing_area_new ();
+  gtk_widget_show (drawing_area);
+  gtk_container_add (GTK_CONTAINER (window), drawing_area);
+  gtk_widget_set_size_request (drawing_area, WIDTH, HEIGHT);
+  g_signal_connect (drawing_area, "draw", G_CALLBACK (draw), NULL);
+
+  g_timeout_add (50, (GSourceFunc) timer, drawing_area);
+
+  gtk_main ();
+  return 0;
+}
diff --git a/20211129/pendulum-2.c b/20211129/pendulum-2.c
new file mode 100644
index 0000000000000000000000000000000000000000..4fbad9a50cc595e92fbb1075dd01405a08e84001
--- /dev/null
+++ b/20211129/pendulum-2.c
@@ -0,0 +1,69 @@
+#include <gtk/gtk.h>
+#include <math.h>
+
+#define WIDTH 320
+#define HEIGHT 240
+#define GAP (HEIGHT / 20)
+#define r GAP
+#define visual_length (HEIGHT - 2 * GAP - r)
+
+#define phi0 (-0.5)
+#define omega0 0.0
+#define t0 0.0
+#define g 9.81
+#define l 1.0
+#define dt 0.02
+
+double t = t0;
+double phi = phi0;
+double omega = omega0;
+
+gboolean draw (GtkWidget *widget, cairo_t *c, gpointer data)
+{
+  GdkRGBA orange = { 1.0, 0.5, 0.0, 1.0 };
+
+  int x = WIDTH / 2 + visual_length * sin (phi);
+  int y = GAP + visual_length * cos (phi);
+
+  gdk_cairo_set_source_rgba (c, &orange);
+  cairo_move_to (c, WIDTH / 2, 10);
+  cairo_line_to (c, x, y);
+  cairo_stroke (c);
+  cairo_arc (c, x, y, r, 0, 2 * G_PI);
+  cairo_fill (c);
+
+  return FALSE;  /* TRUE to stop other handlers from being invoked for the event.
+                    FALSE to propagate the event further. */
+}
+
+gboolean timer (GtkWidget *widget)
+{
+  t += dt;
+  phi += omega * dt;
+  omega += - dt * g / l * phi;
+
+  gtk_widget_queue_draw_area (widget, 0, 0, WIDTH, HEIGHT);
+  g_timeout_add (50, (GSourceFunc) timer, widget);
+  return FALSE;
+}
+
+int main (int argc, char **argv)
+{
+  gtk_init (&argc, &argv);
+
+  GtkWidget *window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+  gtk_widget_show (window);
+  gtk_window_set_title (GTK_WINDOW (window), "Hello");
+  g_signal_connect (window, "destroy", G_CALLBACK (gtk_main_quit), NULL);
+
+  GtkWidget *drawing_area = gtk_drawing_area_new ();
+  gtk_widget_show (drawing_area);
+  gtk_container_add (GTK_CONTAINER (window), drawing_area);
+  gtk_widget_set_size_request (drawing_area, WIDTH, HEIGHT);
+  g_signal_connect (drawing_area, "draw", G_CALLBACK (draw), NULL);
+
+  g_timeout_add (50, (GSourceFunc) timer, drawing_area);
+
+  gtk_main ();
+  return 0;
+}
diff --git a/20211129/pendulum-3.c b/20211129/pendulum-3.c
new file mode 100644
index 0000000000000000000000000000000000000000..35b0b67aeb0d11aa2a81aba204c97ca96504ad89
--- /dev/null
+++ b/20211129/pendulum-3.c
@@ -0,0 +1,86 @@
+#include <gtk/gtk.h>
+#include <math.h>
+
+#define WIDTH 320
+#define HEIGHT 240
+#define GAP (HEIGHT / 20)
+#define r GAP
+#define visual_length (HEIGHT - 2 * GAP - r)
+
+#define phi0 (-0.5)
+#define omega0 0.0
+#define t0 0.0
+#define g 9.81
+#define l 1.0
+#define dt 0.02
+
+double t = t0;
+double phi_with_sin = phi0;
+double omega_with_sin= omega0;
+double phi_without_sin = phi0;
+double omega_without_sin= omega0;
+
+void draw_pendulum (cairo_t *c, double phi, GdkRGBA *colour)
+{
+  int x = WIDTH / 2 + visual_length * sin (phi);
+  int y = GAP + visual_length * cos (phi);
+
+  gdk_cairo_set_source_rgba (c, colour);
+  cairo_move_to (c, WIDTH / 2, 10);
+  cairo_line_to (c, x, y);
+  cairo_stroke (c);
+  cairo_arc (c, x, y, r, 0, 2 * G_PI);
+  cairo_fill (c);
+}
+
+gboolean draw (GtkWidget *widget, cairo_t *c, gpointer data)
+{
+  GdkRGBA blue   = { 0.0, 0.5, 1.0, 1.0 };
+  GdkRGBA orange = { 1.0, 0.5, 0.0, 1.0 };
+  GdkRGBA green  = { 0.0, 0.5, 0.0, 1.0 };
+
+  double A = phi0;
+  double B = 0.5 * M_PI;  /* 90° */
+  double phi_analytic = A * sin (sqrt (g / l) * t + B);
+
+  draw_pendulum (c, phi_with_sin, &blue);
+  draw_pendulum (c, phi_without_sin, &orange);
+  draw_pendulum (c, phi_analytic, &green);
+
+  return FALSE;  /* TRUE to stop other handlers from being invoked for the event.
+                    FALSE to propagate the event further. */
+}
+
+gboolean timer (GtkWidget *widget)
+{
+  t += dt;
+  phi_with_sin += omega_with_sin * dt;
+  omega_with_sin += - dt * g / l * sin (phi_with_sin);
+  phi_without_sin += omega_without_sin * dt;
+  omega_without_sin += - dt * g / l * phi_without_sin;
+
+  gtk_widget_queue_draw_area (widget, 0, 0, WIDTH, HEIGHT);
+  g_timeout_add (50, (GSourceFunc) timer, widget);
+  return FALSE;
+}
+
+int main (int argc, char **argv)
+{
+  gtk_init (&argc, &argv);
+
+  GtkWidget *window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+  gtk_widget_show (window);
+  gtk_window_set_title (GTK_WINDOW (window), "Hello");
+  g_signal_connect (window, "destroy", G_CALLBACK (gtk_main_quit), NULL);
+
+  GtkWidget *drawing_area = gtk_drawing_area_new ();
+  gtk_widget_show (drawing_area);
+  gtk_container_add (GTK_CONTAINER (window), drawing_area);
+  gtk_widget_set_size_request (drawing_area, WIDTH, HEIGHT);
+  g_signal_connect (drawing_area, "draw", G_CALLBACK (draw), NULL);
+
+  g_timeout_add (50, (GSourceFunc) timer, drawing_area);
+
+  gtk_main ();
+  return 0;
+}
diff --git a/20211129/pendulum-4.c b/20211129/pendulum-4.c
new file mode 100644
index 0000000000000000000000000000000000000000..1a08e32735336064af72ce6f332299d14ff66218
--- /dev/null
+++ b/20211129/pendulum-4.c
@@ -0,0 +1,86 @@
+#include <gtk/gtk.h>
+#include <math.h>
+
+#define WIDTH 320
+#define HEIGHT 240
+#define GAP (HEIGHT / 20)
+#define r GAP
+#define visual_length (HEIGHT - 2 * GAP - r)
+
+#define phi0 (-5.0 / 180.0 * M_PI)
+#define omega0 0.0
+#define t0 0.0
+#define g 9.81
+#define l 1.0
+#define dt 0.02
+
+double t = t0;
+double phi_with_sin = phi0;
+double omega_with_sin= omega0;
+double phi_without_sin = phi0;
+double omega_without_sin= omega0;
+
+void draw_pendulum (cairo_t *c, double phi, GdkRGBA *colour)
+{
+  int x = WIDTH / 2 + visual_length * sin (phi);
+  int y = GAP + visual_length * cos (phi);
+
+  gdk_cairo_set_source_rgba (c, colour);
+  cairo_move_to (c, WIDTH / 2, 10);
+  cairo_line_to (c, x, y);
+  cairo_stroke (c);
+  cairo_arc (c, x, y, r, 0, 2 * G_PI);
+  cairo_fill (c);
+}
+
+gboolean draw (GtkWidget *widget, cairo_t *c, gpointer data)
+{
+  GdkRGBA blue   = { 0.0, 0.5, 1.0, 1.0 };
+  GdkRGBA orange = { 1.0, 0.5, 0.0, 1.0 };
+  GdkRGBA green  = { 0.0, 0.5, 0.0, 1.0 };
+
+  double A = phi0;
+  double B = 0.5 * M_PI;  /* 90° */
+  double phi_analytic = A * sin (sqrt (g / l) * t + B);
+
+  draw_pendulum (c, phi_with_sin, &blue);
+  draw_pendulum (c, phi_without_sin, &orange);
+  draw_pendulum (c, phi_analytic, &green);
+
+  return FALSE;  /* TRUE to stop other handlers from being invoked for the event.
+                    FALSE to propagate the event further. */
+}
+
+gboolean timer (GtkWidget *widget)
+{
+  t += dt;
+  phi_with_sin += omega_with_sin * dt;
+  omega_with_sin += - dt * g / l * sin (phi_with_sin);
+  phi_without_sin += omega_without_sin * dt;
+  omega_without_sin += - dt * g / l * phi_without_sin;
+
+  gtk_widget_queue_draw_area (widget, 0, 0, WIDTH, HEIGHT);
+  g_timeout_add (50, (GSourceFunc) timer, widget);
+  return FALSE;
+}
+
+int main (int argc, char **argv)
+{
+  gtk_init (&argc, &argv);
+
+  GtkWidget *window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+  gtk_widget_show (window);
+  gtk_window_set_title (GTK_WINDOW (window), "Hello");
+  g_signal_connect (window, "destroy", G_CALLBACK (gtk_main_quit), NULL);
+
+  GtkWidget *drawing_area = gtk_drawing_area_new ();
+  gtk_widget_show (drawing_area);
+  gtk_container_add (GTK_CONTAINER (window), drawing_area);
+  gtk_widget_set_size_request (drawing_area, WIDTH, HEIGHT);
+  g_signal_connect (drawing_area, "draw", G_CALLBACK (draw), NULL);
+
+  g_timeout_add (50, (GSourceFunc) timer, drawing_area);
+
+  gtk_main ();
+  return 0;
+}
diff --git a/20211129/pendulum.pdf b/20211129/pendulum.pdf
new file mode 120000
index 0000000000000000000000000000000000000000..7d1d87305cdb8840a248ff2207538d758464f452
--- /dev/null
+++ b/20211129/pendulum.pdf
@@ -0,0 +1 @@
+../common/pendulum.pdf
\ No newline at end of file
diff --git a/20211129/pgscript.sty b/20211129/pgscript.sty
new file mode 120000
index 0000000000000000000000000000000000000000..95c888478c99ea7fda0fd11ccf669ae91be7178b
--- /dev/null
+++ b/20211129/pgscript.sty
@@ -0,0 +1 @@
+../common/pgscript.sty
\ No newline at end of file
diff --git a/20211129/pgslides.sty b/20211129/pgslides.sty
new file mode 120000
index 0000000000000000000000000000000000000000..5be1416f4216f076aa268901f52a15d775e43f64
--- /dev/null
+++ b/20211129/pgslides.sty
@@ -0,0 +1 @@
+../common/pgslides.sty
\ No newline at end of file