Das Kommunikationsmodul

Das Kommunikationsmodul hat die Aufgabe, über eine angegebene parallele Schnittstelle mit den angschlossenen Geräten zu kommunizieren. Dieses Modul ist eigentlich unabhängig von der Qt - Bibliothek und könnte auch ohne deren Verwendung implementiert werden. Um das Signal - Slot - Konzept nutzen zu können, welches eine einfache Verbindung zwischen den Modulen ermöglicht, ist aber auch die zur Kommunikation entwickelte Klasse von einer Qt - Klasse, und zwar von der Basisklasse QObject, abgeleitet.

Quellcode

Headerdatei des Objekts

#ifndef __parcomm_h
	#define __parcomm_h
	#include <qobject.h>
	#include <stdio.h>
	#include <unistd.h>
	#include <fcntl.h>
	#include <sys/stat.h>
	#include <sys/types.h>
	#include "definitionen.h"

	class ParComm: public QObject
	{
		Q_OBJECT

		public:
			static ParComm* getPort (int port_id = PAR1);
			~ParComm ();

		private:
			ParComm (int port_id);
			int rasen,
			    strauch,
			    blume,
			    biotop,
			    automatik,
			    portdev,
			    portid;

		public slots:
			void rasen_ein() {rasen = 1;}
			void rasen_aus() {rasen = 0;}
			void strauch_ein() {strauch = 1;}
			void strauch_aus() {strauch = 0;}
			void blume_ein() {blume = 1;}
			void blume_aus() {blume = 0;}
			void biotop_ein() {biotop = 1;}
			void biotop_aus() {biotop = 0;}
			void automatik_ein() {automatik = 1;}
			void automatik_aus() {automatik = 0;}
			void pruefen(tStatus*);
	};
#endif

Implementierung des Objekts

#include "parcomm.h"
#include <sys/io.h>

ParComm::ParComm (int port)
{
	rasen = 0;
	blume = 0;
	strauch = 0;
	biotop = 0;
	automatik = 1;
	portid = port;
	portdev = open ("/dev/port", O_RDWR);
}

ParComm* ParComm::getPort (int port)
{
	if (!ioperm(port, 2, 1))
		return new ParComm(port);
	else
		return NULL;
}

ParComm::~ParComm ()
{
	char ausgang = AUS;
	write (portdev, &ausgang, 1);
	close (portdev);
}

void ParComm::pruefen(tStatus *sysstat)
{
	unsigned char status,
		ergebnis = AUS;
	lseek (portdev, portid+1, SEEK_SET);
	read (portdev, &status, 1);
	sysstat->regenwasser = (status & SCHWIMMER_R) ? 0 : 27;
	sysstat->regen = !(status & REGEN);
	if (automatik)
	{
		if (status & REGEN)
		{
			if (!(status & FEUCHT_BLUME))
			{
				ergebnis |= BLUME_EIN;
				sysstat->blumen = 1;
			}
			else
				sysstat->blumen = 0;
			if (!(status & FEUCHT_RASEN))
			{
				ergebnis |= RASEN_EIN;
				ergebnis |= STRAUCH_EIN;
				sysstat->rasen = 1;
				sysstat->strauch = 1;
			}
			else
			{
				sysstat->rasen = 0;
				sysstat->strauch = 0;
			}
			if (status & SCHWIMMER_B && ergebnis == AUS)
			{
				ergebnis |= BIOTOP_EIN;
				sysstat->biotop = 1;
			}
			else
				sysstat->biotop = 0;
		}
	}
	else
	{
		if (rasen)
		{
			ergebnis |= RASEN_EIN;
			sysstat->rasen = 1;
		}
		else
			sysstat->rasen = 0;
		if (strauch)
		{
			ergebnis |= STRAUCH_EIN;
			sysstat->strauch = 1;
		}
		else
			sysstat->strauch = 0;
		if (blume)
		{
			ergebnis |= BLUME_EIN;
			sysstat->blumen = 1;
		}
		else
			sysstat->blumen = 0;
		if (biotop)
		{
			ergebnis |= BIOTOP_EIN;
			sysstat->biotop = 1;
		}
		else
			sysstat->biotop = 0;
	}
	sysstat->quelle = AUS;
	if (ergebnis != AUS)
	{
		if (ergebnis & BIOTOP_EIN)
		{
			if (!(status & SCHWIMMER_R))
			{
				ergebnis |= QUELLE_REGEN;
				sysstat->quelle = QUELLE_REGEN;
			}
			else
			{
				ergebnis |= QUELLE_LEITUNG;
				sysstat->quelle = QUELLE_LEITUNG;
			}
		}
		else
		{
			if (!(status & SCHWIMMER_R))
			{
				ergebnis |= QUELLE_REGEN;
				sysstat->quelle = QUELLE_REGEN;
			}
			else
			{
				ergebnis |= QUELLE_BRUNNEN;
				sysstat->quelle = QUELLE_BRUNNEN;
			}
		}
	}
	lseek (portdev, portid, SEEK_SET);
	write (portdev, &ergebnis, 1);
}

Erklärung

Anstelle eines öffentlichen Konstruktors enthält die Klasse ParComm einen privaten Konstruktor und eine öffentliche statische Methode, die ein Objekt der eigenen Klasse zurückliefern kann.
Dieser Ansatz wurde gewählt, da beim Anlegen des Objekts der Fehler auftreten kann, dass der Benutzer keine Rechte hat, auf die Schnittstellen des Systems zuzugreifen. In diesem Fall darf kein Objekt angelegt werden.

Die statische Methode getPort versucht in einem ersten Schritt, die Zugriffsberechtigung auf die gewünschte Schnittstelle zu erhalten. Nur wenn dieser Schritt erfolgreich war, liefert die Methode auch tatsächlich ein Objekt der Klasse ParComm zurück; im Fehlerfall wird ein NULL - Zeiger zurückgeliefert.

Im privaten Konstruktor werden die internen Variablen initialisiert sowie die Gerätedatei /dev/ports für Lese- und Schreibzugriff geöffnet. Die Datei ist offen, solange das Objekt existiert; erst im Destruktor wird sie wieder geschlossen, nachdem zuvor die Anlage ausgeschaltet wurde.

Alle öffentlichen Slots bis auf den Slot pruefen(tStatus*) setzen nur die internen Variablen, um den vom Anwender gewünschten Status der Anlage zu garantieren. Keiner dieser Slots führt sofort eine Lese- oder Schreiboperation auf die Schnittstelle aus.

Der Slot pruefen(tStatus*), der vom Steuerungsfenster durch den enthaltenen Timer in periodischen Abständen aktiviert wird, liest das Statusregister der gewählten parallelen Schnittstelle aus und berechnet aus den gelesenen Werten und dem Inhalt der internen Variablen, die den Soll - Status der Anlage beschreiben, den Wert, der in das Datenregister geschrieben werden muss, und schreibt diesen anschließend in das Register. Die Vorgehensweise bei diesem Prüfvorgang wird duch das folgende Struktogramm verdeutlicht.

Struktogramm zum Ein- und Ausschalten der Beregnungsanlage