Hallo miteinander Ich habe ein kleines Problem. Ich bin momentan am Programmieren einer Klasse für ein Projekt (mit einem STM32). Die STM-Lib stellt auch schon Funktionen und so weiter zur verfügung. Wie kann ich es jetzt lösen, dass ein Interrupt eine Funktion in der Klasse aufruft, obwohl im Interrupt keine neue Instanz der KLasse erstellt werden soll? Also die Funktion auf eine andere "mappen"? Besten Dank für die Antwort MFG Patrick
Hallo Patrick, ich bin mir nicht sicher ob ich Deine Frage richtig verstanden habe. Meinst Du evtl ein Singleton? So wie
1 | ret = class.getInstance()->function(); |
Grüsse, R.
Ich versuchs nochmals zu erklähren:
1 | class ComPort{ |
2 | private:
|
3 | uint8_t rxBuffer[256]; |
4 | uint8_t txBuffer[256]; |
5 | |
6 | public:
|
7 | Send(void); |
8 | Get(void); |
9 | TimeoutISR(void); |
10 | }
|
11 | |
12 | void ComPort::TimeoutISR (void){ |
13 | // RX-Daten bearbeiten
|
14 | }
|
15 | |
16 | |
17 | void USART1_IRQHandler (void){ |
18 | TimeoutISR(); // entweder |
19 | |
20 | rxBuffer[]... // oder |
21 | }
|
In der Klasse ComPort ist die Funktion "TimeoutISR", die mir ein Flag in der Klasse selber setzen soll, oder die Daten aus dem rxBuffer der durch einen DMA bedient wird verarbeiten. Die Funktion USART1_IRQHandler wird vom Controller selber aufgerufen. Jetzt kann ich das verarbeiten nicht in diese ISR nehmen, da weder rxBuffer noch die Funktion TimeoutISR bekannt sind (die Instanz wird im main oder sonst wo gemacht). Wie kann ich jetzt also erreichen, dass die Funktion TimeoutISR von USART1_IRQHandler aufgerufen wird, ohne eine neue Instanz in der ISR zu erzeugen?
Patrick B. schrieb: > Wie kann ich jetzt also erreichen, dass die Funktion TimeoutISR von > USART1_IRQHandler aufgerufen wird, ohne eine neue Instanz in der ISR zu > erzeugen? Den Weg zurück schaffst du nur, in dem du der freistehenden Funktion eine Möglichkeit gibst, an das Objekt ranzukommen, deren Methoden du benutzen willst. Zb. in dem du eine globale Variable machst (zb. einen Pointer oder ev. sogar direkt das Objekt), das auch in USART1_IRQHandler bekannt ist. Anders geht es nicht. Um eine Memberfunktion eines Objektes aufzurufen, benötigst du Zugang zum Objekt.
Das würde ich dann wirklich mit einem Singleton lösen. siehe http://de.wikibooks.org/wiki/C++-Programmierung:_Entwurfsmuster:_Singleton In Deinem Fall:
1 | class ComPort{ |
2 | private:
|
3 | uint8_t rxBuffer[256]; |
4 | uint8_t txBuffer[256]; |
5 | |
6 | static ComPort* instance; |
7 | public:
|
8 | static ComPort* getInstance(void); |
9 | Comport () {}; |
10 | |
11 | Send(void); |
12 | Get(void); |
13 | TimeoutISR(void); |
14 | }
|
15 | |
16 | ComPort* ComPort::instance = 0; |
17 | |
18 | ComPort* ComPort::getInstance(void) |
19 | {
|
20 | if (instance == 0) instance = new ComPort(); |
21 | |
22 | return (instance); |
23 | }
|
24 | |
25 | |
26 | void ComPort::TimeoutISR (void){ |
27 | // RX-Daten bearbeiten
|
28 | |
29 | ComPort::getInstance()->meineFunktion(); |
30 | }
|
Das ist nur Beispiel Code. :-) Grüsse, R.
Rene H. schrieb: > Das würde ich dann wirklich mit einem Singleton lösen. > > siehe > http://de.wikibooks.org/wiki/C++-Programmierung:_Entwurfsmuster:_Singleton Ja, ist eine Möglichkeit. Schwieriger wirds, wenn es nicht nur einen COM-Port gibt, sondern deren mehrerer. Das kann dann soweit gehen, dass man aktiv in main ein bestimmtes Objekt benennt und an den IRQ-Handler bindet, in dem man zu jedem IRQ-Handler eine zugehörige Pointer-Variable schafft (oder auch eine Liste von derartigen Pointern), in die diese Verknüpfung eingetragen wird, so dass der IRQ-Handler über den Pointer eine Memberfunktion aufrufen kann. Ist halt immer eine Frage dessen, wie universell man das ganze benötigt. Wenns ganz allgemein sein soll, muss man mehr Aufwand treiben.
Das ist natürlich so. Die Fragestellung gab aber keinen Hinweis dazu. Im Gegenteil. Ich vermute, dass das Singleton Pattern bereits die Frage "überbeantwortet". Manchmal wäre es wirklich gut wenn man wüsste mit welchem Wissen die Frage gestellt wird, zum Beispiel auf einer Skala 1-10. Je nach dem erschliesst sich das Ziel der Frage einem genauer und man kann adäquater Antworten. Würde ich eine Analog Frage stellen, dann wäre es sicher für die Antworten hilfreich wenn sie wüssten, wenig Ahnung und könnten dann entsprechend Antworten :-). Nur als Beispiel. Grüsse, R.
>Das würde ich dann wirklich mit einem Singleton lösen.
..., weil es ausgeschlossen ist, dass es jemals einen zweiten COM-Port
geben könnte. Solchen Kot voller GetInstance() habe ich mal geerbt. All
mein Hass... Von der Untestbarkeit ganz zu schweigen. Nicht persönlich
nehmen. </polemik>
Wie Karl Heinz schrieb, bitte irgendwie so lösen:1 | // global |
2 | ComPort* pComportForIRQ(NULL); |
3 | |
4 | void USART1_IRQHandler (void) |
5 | {
|
6 | pComportForIRQ->TimeoutISR(); // entweder |
7 | pComportForIRQ->rxBuffer[]... // oder |
8 | } |
9 | |
10 | int main() |
11 | {
|
12 | ComPort dingens; |
13 | pComportForIRQ = &dingens; |
14 | //usw |
15 | } |
Tom K. schrieb: >>Das würde ich dann wirklich mit einem Singleton lösen. > ..., weil es ausgeschlossen ist, dass es jemals einen zweiten COM-Port > geben könnte. Solchen Kot voller GetInstance() habe ich mal geerbt. All > mein Hass... Von der Untestbarkeit ganz zu schweigen. Nicht persönlich > nehmen. </polemik> > Hi Tom, nein, ich nehm das nicht persönlich, dafür bin ich schon zu lange Entwickler. Das Argument von mehreren COM Ports ist berechtigt, war aber kein Inhalt in der Fragestellung. Deshalb meine Antwort. (Siehe das letzte Post) Nichts desto trotz, was meinst Du mit Untestbarkeit. Ich verstehe das nicht wirklich. Das lässt sich sauber Debuggen und man kann es ebenso ordentlich mit Unit Tests abfangen. Grüsse, R. PS: Die Gassensprache ist bei mir nicht nötig, ich verstehe dennoch was Du meinst :-). Sorry, dieser Seitenhieb musste jetzt sein. Nicht persönlich nehmen. ;-)
Hallo Rene, die Sprache war wirklich daneben, sorry. Inhaltlich bleibe ich dabei, dass Singletons meistens hässlich sind ;). Der geerbte Code war Bildverarbeitung; die Kamera (von der es nur eine geben sollte und gab) war hinter einem Singleton versteckt und wurde von diversen Objekten (Belichtungsregelung, Objekterkennung u.s.w.) angesprochen. Unittests des Objekterkennungsteils (oder was ich wollte: brute force Parameter ausprobieren) mit gespeicherten Beispielbildern wären sehr einfach gewesen, wenn die Objekterkennung die Abhängigkeiten von Belichtungsregelung und Kamera per dependency injection verpasst bekommen hätte. Dann hätte man ihr einfach ein nichtstuendes Belichtungsregelungsobjekt und eine gespeicherte Bilder ausspuckende Mock-Kamera unterschieben können, ohne im existierenden Code herumzupfuschen. So wie es war, wären Unittests nicht ohne angeschlossene Kamera gelaufen oder hätten massive Änderungen an zig Stellen erfordert, die mir bei drohender Deadline und ohne existierende Unittests zu riskant waren. Auch für den OP wäre es vielleicht praktisch, zum Debuggen des Kommunikationsprotokolls einen gefälschten Serial Port zu mocken, der, ohne die Hardware zu berühren, vorgegebene Ergebnisse liefert. Ein Singleton macht sowas schwieriger oder erfordert eine Menge Setter, um dessen state nur zu Testzwecken von außen anzupassen, was ich ziemlich unsauber finde. Oder sowas, ohne ComPort irgendwie zu verändern:
1 | // Testen, ob die ISR funktioniert.
|
2 | class FakeComPort: public ComPort |
3 | {
|
4 | public:
|
5 | void Send(void){ } |
6 | void Get(void){ } |
7 | void TimeoutISR(void){ToggleLED(2);} |
8 | };
|
9 | |
10 | //...
|
11 | |
12 | //ComPort dingens;
|
13 | FakeComPort dingens; |
14 | pComportForIRQ = &dingens; |
Hallo Tom Tom K. schrieb: > die Sprache war wirklich daneben, sorry. Kein Problem :-). Ja, dann verstehe ich das in etwa. Man muss aber auch sagen, dass ein Singleton nicht generell schlecht sein muss. Ein Pattern macht nicht überall Sinn wo man es einsetzen könnte. Auch erwarte ich von einer kommerziellen Software, dass ordentliche Klassen- und Sequenzdiagramme vorhanden sind, damit die Wartung einfacher wird. Gut, das ist schön Wetter denken. Ich glaube in meinen 24 Jahren Erfahrungen als Entwickler kam das in etwas zwei mal vor. Grüsse, René
Die Variante mit dem Singleton reicht momentan aus. Später soll sie aber
dann umgebaut werden, damit mehere Comports realisiert werden können.
Eine Frage noch:
Wie werden eigentlich "Event-Funktionen" (weiss nicht ob man diesen so
sagt) bei der nächst tieferen Instanz "registriert"?
Soll heissen, in einer Klasse (z.B. Comport) werden für die benötigten
Interrupts passende Funktionen bereitgestellt. Wie kann man jetzt neue
Eventhandler machen, die dann in den entsprechenden Klassenfunktion
enden?
USART1_IRq -> ComPort1_IRqHandler
USART2_IRq -> ComPort2_IRqHandler
SysTick_Irq -> ComPort1_Ticks
-> ComPort2_Ticks
Das ganze soll dann noch möglichst dynamisch erweiterbar sein.
Beim PC können ja auch z.B. Tastendruck-Events programmiert werden, oder
neu erstellt werden.
Sorry, aber ich steige momentan noch nicht so ganz durch mit dem
abstackten denken.
Besten Dank für die Hilfe
MFG
Auf die Gefahr hin, dass ich jetzt als Pattern Fuzzi abgestempelt werde und man mich zereisst. Guck mal nach dem Observer Pattern. Grüsse, R.
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.