Hallo zusammen, Ich arbeite an einer C++ Klasse für die Kommunikation per RS232. Diese soll sich auch gleich um mein "eigenes" Protokoll kümmern (Header, CRC,...) und direkt in meine (zukünftigen) Projekte integriert werden können. Das Senden von Daten ist auch kein Problem. Aber das Empfangen ist so eine Sache, man hat halt nicht so einen genialen Interrupt wie auf den AVRs. Da kam ich auf die Idee dass die Klasse im Constructor ihren eigenen Thread startet, der sich dann ums Empfangen kümmert. Ist ein ganzes Datenpaket angekommen, soll per Funktionszeiger eine Funktion ausserhalb der Klasse (also im Projekt des Anwenders) aufgerufen und die Daten übergeben werden. Das habe ich nun mal so gemacht, und es funktioniert grundsätzlich auch nicht schlecht. Da mein Programm (mit QT-Creator erstellt) aber von Zeit zu Zeit mal abstürzt, bin ich auf den Hinweis gestossen, dass man beim QT-Creator viele Sachen nicht aus einem Thread heraus machen darf. Vor allem auf GUI-Elemente dürfe man nicht zugreifen, und genau das mache ich momentan. Ich will nämlich die empfangenen Daten gleich in einer Liste auflisten lassen, und ich wüsste nicht wie ich das machen soll, wenn es nicht aus dem Thread heraus gemacht werden darf. Wie kann ich nun also aus dem Hauptthread heraus eine gewisse Funktion aufrufen sobald ein Datenpaket oder ein Byte empfangen wurde? Oder wie macht "man" das sonst? Natürlich sollte nicht eine Verzögerung von 2 Sekunden eintreten :-) Es sollte auch eine möglichst universelle Lösung sein, damit die Klasse möglichst universell einsetzbar ist. Ausserdem möchte ich die Klasse für Linux und Windows programmieren, um plattformunabhängig zu sein. Vorerst ist aber vorallem die Linux-Variante wichtig, um den Windows-Kram würde ich mich später kümmern. Ich hoffe ihr habt da ein paar gute Tipps :-) freundliche Grüsse Urban
Urban B. schrieb: > Wie kann ich nun also aus dem Hauptthread heraus eine gewisse Funktion > aufrufen sobald ein Datenpaket oder ein Byte empfangen wurde? du schickt einfach aus denen Thread eine WindowsMessage das jetzt neue Daten das sind. Ich kenn QT aber nicht, aber irgendwo gibt es bei jeder windowsanwendung eine Hauptschleife wo alles nachrichten verarbeitet werden, dort musst du die Nachricht dann auswerten.
Hi, Peter II schrieb: > du schickt einfach aus denen Thread eine WindowsMessage das jetzt neue > Daten das sind. Ich kenn QT aber nicht, aber irgendwo gibt es bei jeder > windowsanwendung eine Hauptschleife wo alles nachrichten verarbeitet > werden, dort musst du die Nachricht dann auswerten. Ich glaube eben das macht QT irgendwie "im Hintergrund". Jedenfalls gibt es im ganzen Code keine Hauptschleife. Und ob das universell einsetzbar ist wäre ich mir auch nicht so sicher... Μαtthias W. schrieb: > http://stackoverflow.com/questions/638251/how-to-e... Das würde vermutlich funktionieren, aber ich möchte eigentlich eine Lösung haben, die auch ausserhalb von Qt funktioniert. Wenn ich mal eine Konsolenanwendung mache, bei der ich meine Klasse einbinden will, habe ich den ganzen Qt-Kram ja nicht. mfg
Urban B. schrieb: > Ich glaube eben das macht QT irgendwie "im Hintergrund". Jedenfalls gibt > es im ganzen Code keine Hauptschleife. google liefert: http://doc.qt.nokia.com/latest/qwidget.html#winEvent QWidget::winEvent
Du empfängst die Daten von der RS232 in einem Lese-Thread. Die empfangenen Daten legst Du z.B. in einem LIFO ab. Von dort holt es dann ein Verarbeitungs-Thread ab, der die Daten weiter verarbeitet. Somit hat Du Lese-Thread und Verabeitungs-Thread entkoppelt. Im Lese-Thread würde ich keinerlei Datenbearbeitung betrieben. Nur Daten lesen und weiterreichen. Die Funktionalität kannst Du komplett in der Modellschicht unterbringen. Das ist dann auch portierbar. Grüsse
Peter II schrieb: > google liefert: > > http://doc.qt.nokia.com/latest/qwidget.html#winEvent > > QWidget::winEvent Ist aber auch wieder eine reine Qt-Lösung, oder kann man das auch ohne Qt auf diese Weise machen? Markus M. schrieb: > Du empfängst die Daten von der RS232 in einem Lese-Thread. Die > empfangenen Daten legst Du z.B. in einem LIFO ab. Von dort holt es dann > ein Verarbeitungs-Thread ab, der die Daten weiter verarbeitet. Somit hat > Du Lese-Thread und Verabeitungs-Thread entkoppelt. > > Im Lese-Thread würde ich keinerlei Datenbearbeitung betrieben. Nur Daten > lesen und weiterreichen. > > Die Funktionalität kannst Du komplett in der Modellschicht unterbringen. > Das ist dann auch portierbar. Dann könnte ich aber auch gleich die Empfangsfunktion von ausserhalb der Klasse aufrufen lassen, dann kann ich mir die Threads gleich komplett sparen. Das puffern übernimmt ja eh schon das Betriebssystem. Ich finde es aber halt irgendwie ziemlich mühsam, wenn der Anwender dann noch irgend ein Timer oder ähnliches braucht, um die Daten zu empfangen. Wenn die Klasse das alles automatisch übernimmt, und mir meldet wenn was reinkommt, wäre das doch echt komfortabel. Scheint aber wohl nicht so einfach zu sein. Dann muss ich halt doch noch eine Art Timer in meine Programme einbinden... Gibts vielleicht Tipps, wie ich diesen Timer am besten realisiere?
Urban B. schrieb: > Ist aber auch wieder eine reine Qt-Lösung, oder kann man das auch ohne > Qt auf diese Weise machen? ja auch QT zu verzichten. Etweder macht du QT oder nicht. > Dann muss ich halt doch noch > eine Art Timer in meine Programme einbinden der Dann wieder ein Thread ist? oder doch ein QT-Timer - was dann wieder QT ist.
Peter II schrieb: > Urban B. schrieb: >> Ist aber auch wieder eine reine Qt-Lösung, oder kann man das auch ohne >> Qt auf diese Weise machen? > ja auch QT zu verzichten. Etweder macht du QT oder nicht. > >> Dann muss ich halt doch noch >> eine Art Timer in meine Programme einbinden > der Dann wieder ein Thread ist? oder doch ein QT-Timer - was dann wieder > QT ist. Du hast mein Problem erkannt :-) Nein im Ernst, gibt es denn keine gescheite Lösung, die auch unabhängig von Qt oder sonstwas ist? Halt etwas, das nur die C++ Werkzeuge verwendet. Ich möchte nicht für jedes ach so kleines Testprogramm, das ein bisschen mit meinen AVRs plaudern soll, das Rad neu erfinden. Ob ich nun einen Lastwagen oder ein Cabriolet baue, ob aus Stahl oder Kunststoff, ist doch egal, die Räder sind doch immer die gleichen :-)
Urban B. schrieb: > Nein im Ernst, gibt es denn keine gescheite Lösung, die auch unabhängig > von Qt oder sonstwas ist? Halt etwas, das nur die C++ Werkzeuge > verwendet. Du hast dich aber schon auf QT festgelegt, damit musst du dich auch an die Regeln von QT halten. Wenn du nur C++ verwenden willst warum hast du dann QT verwendet? QT nimmt man ja weil man das Rad nicht neu erfinden will, also verzichte auf QT und man es mit den Betriebssystem funktionen oder nutze mit Möglichkeiten von QT.
Peter II schrieb: > Du hast dich aber schon auf QT festgelegt, damit musst du dich auch an > die Regeln von QT halten. Wenn du nur C++ verwenden willst warum hast du > dann QT verwendet? > > QT nimmt man ja weil man das Rad nicht neu erfinden will, also verzichte > auf QT und man es mit den Betriebssystem funktionen oder nutze mit > Möglichkeiten von QT. Du weisst aber schon was Qt, bzw. der Qt Creator ist oder? Damit mache ich halt einfach die GUI, weil das, Zitat: "Mit den Betriebssystem funktionen", reeelativ mühsam werden kann :-) Das Programm wird ja trotzdem in C++ geschrieben, mit all den C++ Features die es halt so gibt. Qt ist quasi eine Erweiterung um die GUI zu gestalten. Wenn du mir was Besseres empfehlen kannst, immer her damit! Ich nutze Qt erst seit kurzem, von dem was ich so gesehen habe scheint das eine ziemlich Gute Sache zu sein, vorallem halt auch um plattformunabhängig zu programmieren. Und jetzt komm bitte nicht mit Java, das kann ich nicht, und habe momentan auch nicht die Zeit um es zu lernen :-)
Urban B. schrieb: > Du weisst aber schon was Qt, bzw. der Qt Creator ist oder? Weißt du es denn? > Das Programm wird ja trotzdem in C++ geschrieben, mit all den C++ > Features die es halt so gibt. Qt ist quasi eine Erweiterung um die GUI > zu gestalten. Qt besteht aus einer ganzen Reihe von Bibliotheken, und eine davon ist für GUI-Programmierung. Es bietet aber viel mehr als nur GUI und hat auch die Möglichkeit, Programme komplett ohne GUI zu schreiben. Man kann natürlich Qt nur für die GUI verwenden und für den ganzen Rest was anderes, aber dann sollte man dafür auch einen guten Grund haben.
Ja, ich weiss schon dass Qt noch eine ganze Menge mehr kann. Ich habe ja auch nie behauptet, dass ich nur die GUI von Qt verwende und sonst nichts. Wenn ich aber eine C++ Klasse für die Kommunikation per RS232 schreibe, möchte ich die entweder mit oder ohne Qt einsetzen können. Das soll ja die Klasse nicht kümmern, ob ich ausserhalb der Klasse Qt verwende oder nicht, die soll einfach tun was sie tun soll. Dabei soll sie aber eine Schnittstelle nach aussen haben, um eben ein empfangenes Paket weiterleiten zu können. Die Frage ist jetzt aber, wie ich diese Schnittstelle möglichst universell realisiere, um flexibel zu sein.
Urban B. schrieb: > Wenn ich aber eine C++ Klasse für die Kommunikation per RS232 schreibe, > möchte ich die entweder mit oder ohne Qt einsetzen können. Das soll ja > die Klasse nicht kümmern, ob ich ausserhalb der Klasse Qt verwende oder > nicht, die soll einfach tun was sie tun soll. im C++ Standard gibt es keine Threads keine Serielle schnittstelle. Also must du ohne QT zwangsläufig Betriebystem funktionen nutzen und bist nicht universell > Dabei soll sie aber eine Schnittstelle nach aussen haben, um eben ein > empfangenes Paket weiterleiten zu können. Die Frage ist jetzt aber, wie > ich diese Schnittstelle möglichst universell realisiere, um flexibel zu > sein. ist ja auch kein Prblem - hast du ja schon gelöst. Nur wenn du jetzt ebend QT nutzen willst musst du auch nach den Regel von QT arbeiten. Also nutze die QT möglichkeiten die Info an den Haupthtread weiterzuleiten.
Ich mach das mit Signal in Thread und Slot im Hauptprogram.
Es gibt die POSIX Thread Library (Pthreads) und die Boost Theads Library. Grüsse
Peter II schrieb: > im C++ Standard gibt es keine Threads keine Serielle schnittstelle. Also > must du ohne QT zwangsläufig Betriebystem funktionen nutzen und bist > nicht universell Mit universell meine ich nicht plattformunabhängig, sondern die Art und Weise, wie ich die Klasse nutze. Dass ich die Serielle Schnittstelle und die Threads für jedes OS einzeln programmieren muss, ist mir egal. Das muss ich ja auch nur einmal machen. Ob ich dann mein Programm aber im Notepad, in Eclipse oder im QT-Creator schreibe, das soll keine Rolle spielen. Das meine ich mit universell. Peter II schrieb: > ist ja auch kein Prblem - hast du ja schon gelöst. Nur wenn du jetzt > ebend QT nutzen willst musst du auch nach den Regel von QT arbeiten. > Also nutze die QT möglichkeiten die Info an den Haupthtread > weiterzuleiten. Das wäre natürlich eine Möglichkeit, dass ich wie bisher einen Thread fürs Empfangen verwende, und für Qt dann extra irgendwas "bastle", damit der Hauptthread dann die Daten bekommt. Ist dann aber eben nicht mehr so universell wie ich das gerne gehabt hätte :-) Ich dachte halt, es gibt bestimmt irgendwas, das ich noch nicht kenne. Ich programmiere erst seit ca. 3 Jahren C und seit einem halben Jahr C++. Aber so wie es hier ausschaut geht das wohl nicht viel komfortabler. Das ist irgendwie doch traurig, dass so etwas simples auf einem uC stinkeinfach, und auf einem PC ziemlich mühsam ist?!
Nur Ein Gast schrieb: > Ich mach das mit Signal in Thread und Slot im Hauptprogram. Und dann sind Signal und Slot also quasi voneinander entkoppelt? Das wäre vielleicht eine Möglichkeit, die bei Verwendung von Qt-Creator funktionieren könnte. Und wenn es ohne Qt sein soll, dann halt einfach mit dem Thread, der eine Funktion per Pointer aufruft. Markus M. schrieb: > Es gibt die POSIX Thread Library (Pthreads) und die Boost Theads > Library. > > Grüsse ääh und was willst du nun damit sagen? :-D Momentan verwende ich einen POSIX Thread.
> die bei Verwendung von Qt-Creator funktionieren QtCreator ist doch "nur" eine Oberfläche, die die Verwendung der Funktionen der QT Library erleichtert. QtCreator nimmt auch nur Dein Programm, jagt es durch einen Compiler und bindet als Library halt ( meisstens ) die Qt Lib dazu. Und deshalb kannst Du die QT Funktionen und Dienste nutzen. Boost bietet auch solche Dienste an..... Posix Thread holst Du Dir doch auch aus einer Library .... ( Ich nenne das jetzt einfach mal zusammengefasst als Schlagwort "Library") Du willst eine Funktion nutzen, die eine wie auch immer geartete Lib bietet. Irgendwann hast Du dich dann halt für die Lib entschieden, die Dir für Dich am besten geeignet scheint. Ok Und nun willst Du, dass das ganze auch für alle anderen Libs portabel sein soll ? Irgendwie ist das zu viel verlangt. > Das > ist irgendwie doch traurig, dass so etwas simples auf einem uC > stinkeinfach, und auf einem PC ziemlich mühsam ist?! Nein - nicht wirklich. Auch der PC verwendet im Endefekt einen UART und seine Interrupts. Nur möchtest Du das auf dem Microcontroller "von Hand" bearbeiten. Ok so weit. Auf dem PC geht das natürlich auch. Unter DOS kann man das genau so machen. Wenn Du aber eine Betriebssystem verwenden möchtest, dass für Dich die Hardware versteckt, und noch Multitasking macht und noch ne GUI hat und das ganze Buffern übernimmt usw. usw. - dann wird halt nicht mehr sooo übersichtlich und auf den ersten Blick verständlich. Wenn Du auf dem Microcontroller ein Betriebsystem laufen lässt, dann sieht es dort doch ganze ähnlich aus. Nimm nen LPC3131 mit Linux, oder nen ARM mit Embedded Windows oder QNX oder was auch immer. Von mir aus PicoOS auf nem AVR. Und schon hast Du die gleichen "Probleme" wie auf dem PC. Du hast Dich für ein System entschieden, dass Dir Arbeit abnehmen soll - und diese Systeme sind halt nicht immer alle vollständig untereinder kompatibel. Sonst wären sie ja alle gleich Ich denke es ist nicht abhängig von Microcontroller / PC. Ok - PC Hardware ist komlexer wie Microcontroller Hardware.
> Ob ich dann mein Programm aber im > Notepad, in Eclipse oder im QT-Creator schreibe, das soll keine Rolle > spielen. Das meine ich mit universell. Das spielt keine Rolle. Ich schreibe meine QT Programm manchmal mit QtCreator, aber auch mit VI, Joe, Notepad .... Geht auch mit Eclipse. Das eigentlich wichtige ist, wie Du es durch dem Compiler jagst und welche Lib's Du verwendest und dazu linkst. Ob Du das mit QtCreator machst, oder mit VI und Makefile, oder gar mit EdLin und dann den Compiler und Linker - von mir aus - mit den entsprechenden Parametern von Hand aufrufst .... gehen tut das alles. Das eine ist bequemer, das andere nicht. Aber die Funktion Deines Programmes und der verwendeten Libraries wird sich dadurch nicht ändern.
OK Ihr habt ja alle recht :-) Ich kann mich aber irgendwie nicht so richtig mit dem Gedanken anfreunden, dass ich für ein winzig kleines Kommandozeilenprogramm auch noch die Qt-Libs verwenden muss, einzig und allein nur um meine eigene RS232-Klasse nutzen zu können. Das scheint mir irgendwie ein bisschen wie mit Kanonen auf Spatzen geschossen. Naja, dann mache ich es halt doch so, dass das eigene Programm die RS232-Klasse ständig pollen muss um Zeichen empfangen zu können. Dann brauche ich keine Threads und kein Qt. Dann muss ich jetzt schauen wie ich bei meinen Qt-Programmen am besten einen Timer realisiere, der nicht als eigenständiger Thread arbeitet, sondern vom Hauptthread aufgerufen wird. mfg
Du könntest deiner Kommunikationsklasse eine Callback-Funktion (oder besser ein Objekt) mitgeben, das sie aufruft, wenn sie eine Nachricht empfangen hat. Nur ganz grob skizziert, will gleich noch weg:
1 | class Callback |
2 | {
|
3 | virtual HandleMessage(const MyMessageType& bla) = 0; |
4 | };
|
5 | |
6 | class RS232Receiver |
7 | {
|
8 | RS232Receiver(Callback& c) : m_foo(c) |
9 | {
|
10 | }
|
11 | |
12 | Callback& m_foo; |
13 | |
14 | void ThreadFunc() |
15 | {
|
16 | ...
|
17 | if (completeMessageReceived) |
18 | m_foo.HandleMessage(someMessage); |
19 | ...
|
20 | }
|
21 | };
|
Du könntest dann eine Klasse von Callback ableiten, die mit der Nachricht entweder direkt etwas tut (simples Konsolenprogramm) oder sie einfach in ein QT-Signal übersetzt und weiterschubst. Die Experten a la Karl Heinz Buchegger werden morgen sicherlich eine viel elegantere Lösung parat haben ;)
Tom K. schrieb: > Du könntest deiner Kommunikationsklasse eine Callback-Funktion (oder > besser ein Objekt) mitgeben, das sie aufruft, wenn sie eine Nachricht > empfangen hat. Ja, so ähnlich habe ich es ja bisher gemacht, halt einfach mit einem Funktionszeiger, den ich meiner Klasse übergebe. Wie "gefährlich" sind eigentlich Threads allgemein, also ohne den Einsatz von Qt? Muss man da auch darauf achten dass verschiedene Threads nicht auf die gleichen Variablen zugreifen dürfen? Muss man wie beim uC einfach volatile Variablen einsetzen? Wenn die Threads eh ziemlich gefährlich werden können, verzichte ich dann wohl doch lieber darauf. Schlussendlich kann "der Anwender" ja mit dem Funktionszeiger machen was er will, was dann gefährlich werden könnte. Ständiges pollen wäre zwar mühsamer für den Anwender, dafür aber auch sicherer.
Jetzt bin ich noch auf eine ganz andere Idee gekommen. Angenommen, ich schreibe statt einer einzelnen Klasse gleich ein ganzes Terminalprogramm. Dieses Programm liest per std::cin die Befehle ein und gibt empfangene Datenpakete, Fehlermeldungen usw. per std::cout aus. Das Empfangen könnte dann ohne Probleme mit einem Thread erfolgen. Dann könnte ich in meinen Programmen diese Anwendung starten, Befehle übergeben und deren Ausgaben einlesen. Wäre das eine gute Idee? Bei Linuxanwendungen sieht man ja häufig, dass für reine Terminalanwendungen eine optionale GUI erhältlich ist, das funktioniert doch auch nach diesem Prinzip, oder? Ein Vorteil dabei wäre auch, dass ich diese Anwendung unter einem bestimmten Pfad abspeicheren kann, und alle meine Programme dort die Konsolenanwendung starten. Gibt es nun mal eine neue Version vom Konsolenprogramm, muss ich lediglich diese eine Datei überschreiben, und alle meine Anwendungen haben gleich die neuste Version :-) mfg
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.