Die Kommunikation über die serielle Schnittstelle

Das Kommunikationsmodul für die serielle Schnittstelle hat die Aufgabe, die Kommunikation mit dem Modem zu realisieren. Es muss Strings zum Modem schicken können. Empfangene Zeichen sollen zu einem String zusammengesetzt und erst dann an das Interpretationsmodul weitergereicht werden, wenn der komplette String empfangen wurde.

Quellcode

Headerdatei des Objekts

#ifndef __sercomm_h
	#define __sercomm_h
	#include <qobject.h>
	#include <string.h>
	#include <termios.h>
	#include <fcntl.h>
	#include <unistd.h>
	#include <qsocketnotifier.h>
	#include "definitionen.h"

	class SerComm: public QObject
	{
		Q_OBJECT
			
		public:
			SerComm (int port, QWidget *main, QObject *parent = NULL, const char *name = NULL);
			~SerComm ();
			void sendCommand (char*);

		private:
			int serport, inbuff_wr;
			char inbuff[300];
			QSocketNotifier *notifier;
			struct termios serial_ori;

		signals:
			void gotLine (char*);

		private slots:
			void dataReady ();
	};
#endif

Implementierung des Objekts

#include "sercomm.h"
#include <stdio.h>
#include <errno.h>
#include "pinform.h"

#define SPEED B19200

SerComm::SerComm (int port, QObject *parent, const char *name)
	:QObject (parent, name), serport (-1), inbuff_wr (0)
{
	int i;
	struct termios serterm;
	
	if ((serport = open ((port == SER1) ? "/dev/ttyS0" : "/dev/ttyS1", O_RDWR)) < 0)
	{
		perror ("Fehler beim Öffnen der seriellen Schnittstelle");
		exit (-1);
	}
	tcgetattr (serport, &serterm);
	serial_ori = serterm;
	serterm.c_lflag &= ~ICANON;

	serterm.c_lflag &= ~(ECHO|ECHOCTL|ECHONL);
	serterm.c_lflag |= HUPCL;
	serterm.c_cc[VMIN] = 1;
	serterm.c_cc[VTIME] = 0;
	serterm.c_oflag &= ~ONLCR;
	serterm.c_iflag &= ~ICRNL;
	cfsetospeed (&serterm, SPEED);
	cfsetispeed (&serterm, SPEED);

	tcsetattr (serport, TCSANOW, &serterm);
	strcpy (inbuff, "AT+CPIN?\r");
	write (serport, inbuff, 9);
	for (i = 0; i < 9; i++)
		read (serport, inbuff, 1);
	i = 0;
	do {
		read (serport, inbuff+i, 1);
		++i;
	} while (inbuff[i-1] != 0x0A);
	inbuff[i-1] = 0x00;
	if (strstr (inbuff, "+CPIN: READY") != NULL)
	{
		strcat (inbuff, " eingeben");
		PinForm *pf = new PinForm (inbuff+7);
		pf->exec();
		sprintf (inbuff, "AT+CPIN=%s\r", pf->getPIN());
		write (serport, inbuff, strlen(inbuff));
		for (i = 0; i < strlen(inbuff); i++)
			read (serport, inbuff+20, 1);
		i = 0;
		do {
			read (serport, inbuff+i, 1);
			++i;
		} while (inbuff[i-1] != 0x0A);
		inbuff[i-1] = 0x00;
		if (strstr(inbuff, "OK") == NULL)
		{
			printf ("PIN war ungültig.\n");
			exit (-2);
		}
	}
	strcpy (inbuff, "AT+CMGF=1\r");
	write (serport, inbuff, strlen(inbuff));
	for (i = 0; i < strlen(inbuff); i++)
		read (serport, inbuff, 1);
	notifier = new QSocketNotifier (serport, QSocketNotifier::Read, NULL);
	connect (notifier, SIGNAL(activated(int)), this, SLOT(dataReady()));
	notifier->setEnabled(TRUE);
}

SerComm::~SerComm ()
{
	tcsetattr (serport, TCSANOW, &serial_ori);
	close (serport);
}

void SerComm::dataReady ()
{
	char c;
	read (serport, &c, 1);
	if (c != 0x0A && c != 0x0D)
		inbuff[inbuff_wr++] = c;
	if (c == 0x0A || c == '>')
	{
		inbuff[inbuff_wr] = 0x00;
		inbuff_wr = 0;
		emit gotLine (inbuff);
	}
}

void SerComm::sendCommand (char *command)
{
	char c;
	write (serport, command, strlen(command));
}

Erklärung

Im Konstruktor wird das serielle Terminal konfiguriert, nachgefragt, ob ein PIN nötig ist und eventuell ein Fenster zum Eingeben des PINs angezeigt und das Nachrichtenformat eingestellt. Anschließend wird der Dateideskriptor der Schnittstelle mit einem QSocketNotifier verbunden, der ein Signal aussendet, sobald Daten zum Lesen an der Schnittstelle angelangt sind. Dadurch ist es möglich, nur dann zu versuchen, Daten zu lesen, wenn auch wirklich Daten angekommen sind. So kann die Oberfläche blockierungsfrei gehalten werden.

Der Destruktor stellt die ursprünglichen Einstellungen der seriellen Schnittstelle wieder her und schließt den Dateideskriptor für die Schnittstelle.

Die Methode sendCommand schickt den ihr übergebenen String an das Modem weiter.

Der Slot dataReady wird vom QSocketNotifier aktiviert. Es wird ein Zeichen von der Schnittstelle gelesen und in einen Puffer geschrieben. Anschließend wird kontrolliert, ob das erhaltene Zeichen den String abschließt. Ist dies der Fall, so wird das Signal gotLine ausgesendet, in dem der Inhalt des Puffers weitergegeben wird.