\documentclass[german, a4paper, headheight=36pt, parskip=true]{scrartcl} \usepackage{hs-el-text} \modul{Echtzeitdatenverarbeitung} \semester{Wintersemester 2020/21} \thema{Dokumentation Bearbeiten} \author{Charlotte Friedemann \und Johannes Theiner} \gruppe{A5} \begin{document} \maketitle \section{Tasks}\label{sec:tasks} Um einen konsistenten Startpunkt zu erhalten werden bei allen Tasks zu Beginn sämtliche vom entsprechenden Task verwendeten Aktoren auf Ausgangsposition zurückgesetzt. \subsection{Drehteller}\label{subsec:task_turntable} Nach dem Zurücksetzen vom Drehteller und des Auswerfers am Eingang fährt der Drehteller zuerst fünf Runden, bei denen der Auswerfer am Ausgang bedingungslos betätigt wird, um Teile die sich vielleicht noch in der Anlage befinden aus dieser zu entfernen. Um eine Synchronisierung zu erlangen wird der Drehteller erst aktiv, wenn Prüfer, Bohrer und Auswerfer mit einer Nachricht auf die Status Mailbox signalisiert haben das sie mit ihren Aktionen fertig sind. Liegt auf mindestens einem Sensor(Eingang, Tester oder Bohrer) ein Teil wird der Drehteller aktiviert und erst wieder deaktiviert, wenn dieser wieder in Position ist. Nun wird den anderen Tasks über Nachrichten signalisiert das diese aktiv werden können und der Prozess beginnt erneut. \subsection{Prüfer}\label{subsec:task_tester} Sobald der Prüfer aktiv werden darf(Nachricht auf Status Mailbox) wird überprüft ob ein Teil auf dem Sensor liegt. Liegt ein Teil auf dem Sensor, fährt der Prüfer aus und das Testergebnis wird dem Bohrer über eine Nachricht mitgeteilt. Nun wird der Prüfer eingefahren und der Drehteller kann wieder aktiv werden. Der Prozess beginnt nun wieder von vorne. \subsection{Bohrer}\label{subsec:task_drill} Wird ein Werkstück durch den Sensor erkannt wird abhängig von der Nachricht des Prüfers der Bohrer angeschaltet, heruntergefahren und das Werkstück festgehalten. Nach einer kurzen Wartezeit wird der Bohrer wieder nach oben gefahren, ausgeschaltet und das Werkstück losgelassen. Nachdem der Auswerfer über ein zu erwartendes Teil benachrichtigt wurde, wird die Kontrolle wieder an den Drehteller übergeben. \subsection{Auswerfer}\label{subsec:output} Da für den Auswerfer keine Sensoren existieren sendet der Bohrer den Status seines Sensors per Nachricht an den Auswerfer, der auf Basis dieser auslöst. \subsection{Diagramme}\label{subsec:diagrams} \begin{figure}[H] \centering \begin{minipage}{.5\textwidth} \centering \begin{plantuml} @startuml scale 150 width !include https://raw.githubusercontent.com/bharatrajagopalan/plantuml-styles/master/activity_skin.pu start :Drehteller ausschalten; :Auswefer Eingang ausschalten; repeat :Drehteller kurz anschalten; :Auswerfer kurz betätigen; repeat while(5 Durchläufe ?) repeat :Prüfer fertig?< :Bohrer fertig?< :Auswerfer fertig?< :Teil im Prüfer?< :Teil im Bohrer?< if(Teil auf einem Sensor ?) then (true) :Drehteller anschalten; if(Sensor Drehteller in Position ?) then (true) :Drehteller auschalten; endif endif :Drehteller fertig> repeatwhile() kill @enduml \end{plantuml} \captionof{figure}{SDL Diagramm Drehteller} \label{fig:sdl-turntable} \end{minipage}% \begin{minipage}{.5\textwidth} \centering \begin{plantuml} @startuml !include https://raw.githubusercontent.com/bharatrajagopalan/plantuml-styles/master/activity_skin.pu start :Prüfer einfahren; :Prüfer fertig> repeat :Drehteller fertig?< if(Werkstück vorhanden ?) then (ja) :Prüfer ausfahren; if(Werkstück in Normallage ?) then (ja) :Sende Bohrer(an)> else (nein) :Sende Bohrer(aus)> endif :Prüfer einfahren; else (nein) endif :Prüfer fertig> repeatwhile() kill @enduml \end{plantuml} \captionof{figure}{SDL Diagramm Prüfer} \label{fig:sdl-tester} \end{minipage} \end{figure} \begin{figure}[H] \centering \begin{minipage}{.5\textwidth} \centering \begin{plantuml} @startuml scale 150 width !include https://raw.githubusercontent.com/bharatrajagopalan/plantuml-styles/master/activity_skin.pu start :Bohrer ausschalten; :Bohrer hochfahren; :Werkstück loslassen; :Bohrer fertig> repeat :Drehteller fertig?< if(Werkstück vorhanden?) then(ja) :Empfange Lage des Werkstücks< :Sende Auswerfer> if(Teil in Normallage?) then(ja) :Werkstück festhalten; :Bohrer anschalten; :Bohrer herunterfahren; :Warte bis Bohrer unten; :Bohrer hochfahren; :Warte bis Bohrer oben; :Bohrer ausschalten; :Werkstück loslassen; else(nein) endif else (nein) endif :Bohrer fertig> repeatwhile() kill @enduml \end{plantuml} \captionof{figure}{SDL Diagramm Bohrer} \label{fig:sdl-drill} \end{minipage}% \begin{minipage}{.5\textwidth} \centering \begin{plantuml} scale 250 width @startuml !include https://raw.githubusercontent.com/bharatrajagopalan/plantuml-styles/master/activity_skin.pu start :Auswerfer einfahren; :Auswerfer fertig> repeat :Drehteller fertig?< :Auswerfer< if(Auswerfen ?) then (ja) :Auswerfer betätigen; endif :Auswerfer fertig> repeatwhile() kill @enduml \end{plantuml} \captionof{figure}{SDL Diagramm Auswerfer} \label{fig:sdl-output} \end{minipage} \end{figure} \section{Hilfsfunktionen}\label{sec:functions} Zur Vereinfachung des Leseflusses und der besseren Nachvollziehbarkeit des Codes werden wiederkehrende Programmteile in Hilfsfunktionen ausgelagert. Passiert während des Durchlaufens der einzelnen Funktionen ein Fehler, so wird die erste hier beschriebene Hilfsfunktion aufgerufen. \subsection{void end(bool fail)}\label{subsec:void end(bool fail)} Bei Aufruf dieser Hilfsfunktion werden sämtliche Taks, Mailboxen, Modbus-Verbindungen und Semaphoren deinitialisiert und der Timer gestoppt. Falls der Übergabeparameter \mintinline{c}{fail == true} ist, so wird eine entsprechende Nachricht auf der Konsole ausgegeben. \subsection{int readAll(int type, int *result)}\label{subsec:int readAll(int type, int *result)} Das Auslesen aller zur Verfügung stehenden Bits, abhängig vom Typ der Verbindung, erfolgt mithilfe der nicht Thread-sicheren Funktion readAll. Dabei wird dieser Funktion sowohl der Verbindungs-Typ (\mintinline{c}{DIGITAL_IN, DIGITAL_OUT, ANALOG_IN, ANALOG_OUT}), als auch ein Pointer auf den Speicherplatz übergeben, an welchem das Ergebnis gespeichert wird. Bei erfolgreichem Durchlaufen dieser Funktion wird eine 0 zurückgegeben, ansonsten eine 1. \subsection{int readData(int part)}\label{subsec:int readData(int part)} Im Gegensatz zur Hilfsfunktion \mintinline{c}{readAll()} liest die Funktion readData nur ein einzelnes Bit aus und gibt dieses zurück. Damit die Richtigkeit der Daten während des Auslesens gewährleistet werden kann, ist diese Funktion mithilfe einer Semaphore Thread-sicher gemacht worden. Nach dem Auslesen aller Bits des Modbus wird der Wert der Funktion \mintinline{c}{readAll()} mit der in \mintinline{c}{part} übergebenen Bitmaske verundet und somit isoliert. Dieses einzelne Bit wird nun in \mintinline{c}{result} gespeichert und die Semaphore wieder freigegeben. Bei fehlerfreiem Aufruf der \mintinline{c}{readAll()}-Funktion wird das spezifizierte einzelne Bit zurückgeben, falls nicht, so wird in die \mintinline{c}{end()}-Hilfsfunktion gesprungen und alle Tasks, Mailboxen, etc deinitialisiert und gestoppt. \subsection{void disable(int actor)}\label{subsec:void disable(int actor)} Diese Funktion deaktiviert den im Übergabeparameter spezifizierten Aktor. Da auch in diesem Fall die Daten aus dem Modbus während des Lesezugriffs nicht verändert werden dürfen ist diese Funktion Thread-sicher. Zur Kommunikation mit dem jeweiligen Aktor wird die gesamte Bitfolge über \emph{readAll()} ausgelesen. Ist dies ohne Fehler geschehen, so wird die empfangene Bitfolge mit der negierten Bitmaske des anzusprechenden Aktors verundet. Diese neue, sich nur in einem Bit unterscheidende Bitfolge wird auf den Modbus geschrieben und die Semaphore freigegeben. \subsection{void sendMail(MBX * mailbox, int msg)}\label{subsec:void sendMail(MBX * mailbox, int msg)} Das Senden einer blockierenden Nachricht (\mintinline{c}{msg}) an eine über mailbox spezifierte Mailbox wird mithilfe dieser Funktion realisiert. \subsection{void sendMailNonBlocking(MBX * mailbox, int msg)}\label{subsec:void sendMailNonBlocking(MBX * mailbox, int msg)} Im Unterschied zur Funktion \mintinline{c}{sendMail()} wird hier eine nicht-blockierende Nachricht (msg) an die in mailbox spezifizierte Mailbox gesendet. \subsection{int receiveMail(MBX * mailbox)}\label{subsec:int receiveMail(MBX * mailbox)} Diese Hilfsfunktion fasst das Erhalten einer blockierenden Nachricht an der im Übergabeparameter spezifizierten Mailbox zusammen und gibt den Nachrichteninhalt zurück. \subsection{int receiveMailNonBlocking(MBX * mailbox)}\label{subsec:int receiveMailNonBlocking(MBX * mailbox)} Analog zu \mintinline{c}{receiveMail()} wird auch hier einen Nachricht an der im Übergabeparamter spezifizierten Mailbox erhalten und deren Inhalt zurückgegeben, jedoch ist diese nicht blockierend. \subsection{void sleepMs(int ms)}\label{subsec:void sleepMs(int ms)} Da bei der Kommunikation der Tasks untereinander oder der Abarbeitung an den einzelnen Stationen teilweise Pausen benötigt werden, ist diese Funktion unerlässlich. Dabei wird mithilfe des Übergabeparameters festgelegt, für wie viele Millisekunden ein Tasks pausieren soll. \end{document}