Forum: PC-Programmierung Serieller Port, Linux, C++


von Karl (Gast)


Lesenswert?

Kurze, schmerzlose Frage:
Unter C würde man auf Linux die serielle Schnittstelle wohl über 
termios.h ansprechen.
Gibts da in C++ (ohne Frameworks wie Qt oder Boost) was "moderneres"?

Grüße, Karl

von Matthias H. (experimentator)


Lesenswert?

Um es kurz zu machen, nein. Die Ansteuerung von seriellen oder anderen 
Schnittstellen ist betriebssystem- und hardwarespezifisch und nicht 
Bestandteil der C++-Standardbibliotheken.

von Neuling (Gast)


Lesenswert?

Matthias H. schrieb:
> Um es kurz zu machen, nein. Die Ansteuerung von seriellen oder
> anderen
> Schnittstellen ist betriebssystem- und hardwarespezifisch und nicht
> Bestandteil der C++-Standardbibliotheken.

wxwidgets mit der CTB von Joachim Bürmann konnte das ganz gut, ging 
unter Windows, Linux und MAC OS.

https://iftools.com/opensource/ctb.de.php

von Matthias H. (experimentator)


Lesenswert?

Noch ein kleiner Nachtrag:

termios.h usw. ist nur notwendig, wenn tatsächlich ein Terminal über 
irgendwelche Steuerzeichen angesprochen werden soll.

Für "normale" Anwendungen, wo man nur irgendwelche Daten lesen oder 
schreiben möchte,  wäre das klassische Vorgehen unter UNIX, daß man über 
open() das entsprechende Device aufmacht, über ioctl() Baudrate, 
Handshake-Leitungen u. ä. setzt und über read() und write() Daten liest 
oder schreibt (wahlweise mit asynchronem I/O). Ich würde empfehlen, sich 
eine passende Klassenbibliothek zu suchen oder zumindest eine 
Wrapperklasse zu schreiben, denn mit den nackten Betriebssystemaufrufen 
macht es einfach keinen Spaß, gerade die Fehlerbehandlung.

von Karl (Gast)


Lesenswert?

Ja, das hab ich mir fast gedacht. Ich werde mir dann eben eine 
Wrapperklasse mit "Komfort"routinen schreiben.

Spricht eigentlich irgendwas dagegen, im Konstruktor dieser klasse einen 
neuen (p)thread zu erstellen? Dieser könnte dann Daten nmit select() 
einlesen und einen Puffer befüllen, während das eigentliche Programm 
weiterläuft.

Soviele serielle Verbindungen hat man ja normal nicht offen, sodass 
plötzlich Unmengen an Threads laufen...

von Matthias H. (experimentator)


Lesenswert?

Hallo Karl,

> Spricht eigentlich irgendwas dagegen, im Konstruktor dieser klasse einen neuen
> (p)thread zu erstellen? Dieser könnte dann Daten nmit select() einlesen und
> einen Puffer befüllen, während das eigentliche Programm weiterläuft.

Da spricht nichts dagegen, ich habe das schon öfters so gemacht. 
Meistens mache ich es so, daß die "Arbeitsfunktion" des Threads einen 
Zeiger auf die Objektinstanz der Schnittstellen-Wrapperklasse übergeben 
bekommt und nach den entsprechenden Type Casts eine Worker-Methode in 
der "Schnittstellenklasse" aufruft. Der Zugriff auf den verwendeten 
Puffer muß synchronisiert werden, z. B. über eine Mutex-Semaphore. Eine 
einfache, wenn auch nicht sehr effiziente Möglichkeit für solch einen 
Puffer wäre ein STL-String.

Allerdings mußt Du bei Threads, Semaphoren usw. wiederum eine ganze 
Menge Fehlerbehandlung usw. machen, daher würde ich wirklich empfehlen, 
daß Du eine Klassenbibliothek nimmst und es nicht alles selbst machst, 
es sei denn, um zu lernen, wie es geht.

Tschüß, Matthias

von Karl (Gast)


Lesenswert?

So, war leider die letzten Tage unterwegs und konnte nicht mehr 
reinschaun.
Danke dir Matthias!

Ich bin in C++ nicht so bewandert (deswegen eben diese Fingerübung), 
aber ist ein std::vector<char> nicht besser geeignet als ein 
std::string?
Ich meine, über die Serielle werden ja auch Binärdaten übertragen.

Ansonsten:
Ich habe vor längerer Zeit einen Bootloader (PC-Seite) für meine 
AVR-Projekte geschrieben, in reinem C.
Als Übung wollte ich diesen nun auf C++ umschreiben.
Leider fallen mir hier einige Sachen auf die mich stören.
Allen vorran die Tatsache, dass ich in meinem Klassenheader 
Informationen über die interne Umsetzung preisgeben muss (Stichwort: 
private Attribute).
Und spätestens wenn ich mehrere Klassen habe die andere Klassen als 
Attribut verwenden habe ich dermaßen viele Folge-Includes, dass die 
"oberste" Kompiliereinheit über das halbe Projekt "Bescheid weis".
Das stößt mir bisl sauer auf, weil ich in C sehr darauf geachtet habe, 
Interface (Header) und Implementierung (C-File) zu trennen...

Ich werde das Projekt mal noch abschließen und danach neu beurteilen, ob 
C++ das richtige für mich ist :-)

Grüße,
Karl

von Programmierer (Gast)


Lesenswert?

> Und spätestens wenn ich mehrere Klassen habe die andere Klassen als
> Attribut verwenden habe ich dermaßen viele Folge-Includes, dass die
> "oberste" Kompiliereinheit über das halbe Projekt "Bescheid weis".
> Das stößt mir bisl sauer auf, weil ich in C sehr darauf geachtet habe,
> Interface (Header) und Implementierung (C-File) zu trennen...
Diese Klassen wirst Du als Zeiger oder Objektreferenz übergeben und 
dafür reicht eine "Forward Deklaration". Einen Header musst du dann 
nicht einbinden.

Nur für Datentypen, die kein Zeiger oder eine Referenz sind, musst Du 
Header einbinden.

Du musst dich mit C++ mehr beschäftigen. Möchtest Du das nicht, dann ist 
C++ nicht das richtige für dich!

Gute Buch ist "Der C++ Programmierer" von Ulrich Beymann.

von Matthias H. (experimentator)


Lesenswert?

Hallo Karl,

Karl schrieb:
> So, war leider die letzten Tage unterwegs und konnte nicht mehr
> reinschaun.
> Danke dir Matthias!
>
> Ich bin in C++ nicht so bewandert (deswegen eben diese Fingerübung),
> aber ist ein std::vector<char> nicht besser geeignet als ein
> std::string?
> Ich meine, über die Serielle werden ja auch Binärdaten übertragen.

Im Prinzip hast Du recht, aber Nullbytes sind im Gegensatz zu 
C-"Strings" kein Problem und der Vorteil beim String ist, daß man ihn 
problemlos zum Debuggen mit Standard-I/O-Funktionen auf die Konsole oder 
in eine Datei schreiben kann. Das ist letztenendes Geschmackssache.

> Ansonsten:
> Ich habe vor längerer Zeit einen Bootloader (PC-Seite) für meine
> AVR-Projekte geschrieben, in reinem C.
> Als Übung wollte ich diesen nun auf C++ umschreiben.
> Leider fallen mir hier einige Sachen auf die mich stören.
> Allen vorran die Tatsache, dass ich in meinem Klassenheader
> Informationen über die interne Umsetzung preisgeben muss (Stichwort:
> private Attribute).

Das mußt Du nicht, allerdings ist die Lösung etwas aufwendiger:
1. Basisklasse mit Header schreiben, die nur das im Header exportiert, 
was Du willst und virtuelle Methoden für die von außen sichtbare 
Funktionalität enthält.
2. "Interne" abgeleitete Klasse schreiben, die die weitere 
Funktionalität enthält. Es gibt übrigens keinen Grund, dafür eine 
separate Headerdatei oder Quellcodedatei zu schreiben.
3. "Factory"-Funktion oder -methode zum Erzeugen einer Instanz der 
Klassen schreiben (am besten "public static"-Klassenmethode in der 
Basisklasse; wenn die Basisklasse zusätzlich nur einen Konstruktor hat, 
der private ist, kann man die Klasse dann nur über die Factory-Methode 
instantiieren).
Die Factory-Funktion liefert dann nicht eine Instanz der Basisklasse, 
sondern eine der abgeleiteten Klasse und die Features der abgeleiteten 
Klasse sind dann vor dem Aufrufer, der nur die Headerdatei mit der 
Basisklasse hat, verborgen.
Eine Steigerungsmöglichkeit wäre, daß die Factory-Methode Instanzen 
verschiedener abgeleiteter Klassen zurückliefern kann abhängig von 
Parametern oder Einstellungen.

> Und spätestens wenn ich mehrere Klassen habe die andere Klassen als
> Attribut verwenden habe ich dermaßen viele Folge-Includes, dass die
> "oberste" Kompiliereinheit über das halbe Projekt "Bescheid weis".
> Das stößt mir bisl sauer auf, weil ich in C sehr darauf geachtet habe,
> Interface (Header) und Implementierung (C-File) zu trennen...
>
> Ich werde das Projekt mal noch abschließen und danach neu beurteilen, ob
> C++ das richtige für mich ist :-)

Mal ganz im Ernst, ich bin kein C++-Fan, die Sprache ist furchtbar, aber 
es ist gegenüber C ein deutlicher Fortschritt, weil ich eine weitere 
Abstraktraktionsebene habe. Daß man Strings, diverse Containerklassen u. 
ä. hat, ist bei komplexeren Datenstrukturen ein großer Vorteil. Mit 
etwas Erfahrung geht das Meiste dreimal so schnell wie in C. Ich würde 
heute ohne Not (was bei Microcontrollern natürlich wegen Speicherbedarf 
einschl. Laufzeitumgebung gegeben sein kann) keine reinen C-Projekte 
mehr neu beginnen.
Allerdings sind einige Features mit Vorsicht zu genießen, z. B. ist 
printf() usw. oft handlicher, wenn auch leider fehleranfälliger, als 
iostream.

Tschüß, Matthias

von Programmierer (Gast)


Lesenswert?

Korrektur: Gutes Buch ist "Der C++ Programmierer" von Ulrich Breymann.

von Karl (Gast)


Lesenswert?

Mir sind die Workarounds ("pimpl idiom", "simple pointer") durchaus 
bekannt.
Aber ich finde das irgendwie, nunja, nicht elegant.

@ Matthias: ja, die STL und ihre Container sind schon was feines (wenn 
man denn erstmal nen Überblick hat).
Und ja, iostreams find ich bei einer komplexen Ausgabe auch sehr 
umständlich.
Wobei, in meinem Fall (serielle Verbindung) könnte man den <<-Operator 
wunderbar überladen und zur Ausgabe nutzen.

Gruß,
Karl

von Max (Gast)


Lesenswert?

boost::asio kann auch mit seriellen Schnittstellen arbeiten...

http://www.boost.org/doc/libs/1_54_0/doc/html/boost_asio/overview/serial_ports.html

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.