Moin, ich habe folgenden Aubau: An einer Steuerung (STM32F4) hängen verschiedene gleichartige Geräte (z.B. Netzteile). Diese Geräte werden über RS232, USB-CDC oder I²C angesprochen. Ich würde mir nun gerne eine Art Treiber scheiben (Keil C, RTOS u.a. wegen USB-Host), der dafür sorgt, dass das übergeordnete Programm alle Geräte gleich ansprechen kann. Da gleichzeitig mehrere der Geräte am der Steuerung hängen können, verwalte ich die Dinger mit einem Array. Das Array ist eine Auflistung von struct, die Funktionspointer enthält. Die Funktionspointer zeigen dann auf die Funktionen, die zum Steuern des Geräts benötigt werden. Wie realisiert man das? Bisher habe ich Funktionen, denen noch die Schnittstelle mit übergeben wird. Das würde ich mir - wenn möglich - gerne sparen und die Funktionen nur so aufrufen: Geraet[1]->Licht(AN). Geraet[1] sollte dann halt "wissen", welche Schnittstelle verwendet werden soll. Geraet[0] könnte eine andere Schnittstelle oder im Fall von I²C eine andere Adresse oder beide sein. Moentan würde es so aussehen: Geraet[1]->Licht(Schnittstelle[1],AN) oder Geraet[1]->Licht(Geraet[1]->Schnittstelle,AN) PS: Dass man das auch in C++ erledigen kann, ist mir klar. C ist aber "Kundenvorgabe".
Gast
#4729980
sowas kann man machen .. muss man aber nicht ^^ z.B. linuxlike gibt es diverse I/O funktionen für devices also read/write/open/close/ioctl gibt dazu sogar schon diverse abstractionen zu wo man geräte mit "dev/..." anspricht entweder macht man nun auch structs im treiber so das man mehrere intanzen des treibers laden kann ... wo halt adressen und so gespeichert werden.. jede geraetestruct merkt sich dann die erzeugt instanz im treiber und greift darauf zu oder wenn die peripherie überschaubar ist , dann adressparameter in die geraetestruct ...
Gast
#4729984
Bei einer C++-Klasse würde implizit der this-Pointer an die Funktion übergeben werden. In C musst Du das explizit hinschreiben:
1 | |
Die Schnittstelle ist dann ein Element in der Gerät-Struktur, auf die die Funktion "Licht" zugreift. Wenn Dich das redundante "Geraet[1]" stört, könntest Du den Aufruf höchstens in ein Makro verpacken, so dass es dann in etwa so aussieht:
1 | |
Gast
#4729987
oder du baust dir macros ... um aus Geraet[1]->Licht(Geraet[1]->Schnittstelle,AN) ein Geraet[1]->Lichtmacro(AN) zu erzeugen
> PS: Dass man das auch in C++ erledigen kann, ist mir klar. C ist aber > "Kundenvorgabe". Da könnte man ja auch ganz fies sein und C-Front (den alten C++ nach C Compiler) auskramen. Wenn der Kunde doch C++ in C will. LLVM könnte man für sowas sicher auch einsetzen, damit wurde ja auch ein C++ nach JavaScript Compiler gebaut. Mal gesucht und gefunden: http://llvm.org/releases/3.1/docs/FAQ.html#translatecxx
Rahul D. schrieb: > Bisher habe ich Funktionen, denen noch die Schnittstelle mit übergeben > wird. Das würde ich mir - wenn möglich - gerne sparen und die Funktionen > nur so aufrufen: > > Geraet[1]->Licht(AN). Ich würde Gerät 1 nur so aufrufen wollen: schalte(1,AN); oder schalte(1,AUS); Den ganzen Kram mit den Arrays und Schnittstellenzuordnung brauchst du dann nur einmal, eben in der Funktion schalte(geraetenummer,an_aus).
Gast
#4731723
Jobst Q. schrieb: > Rahul D. schrieb: >> Bisher habe ich Funktionen, denen noch die Schnittstelle mit übergeben >> wird. Das würde ich mir - wenn möglich - gerne sparen und die Funktionen >> nur so aufrufen: >> >> Geraet[1]->Licht(AN). > > Ich würde Gerät 1 nur so aufrufen wollen: > > schalte(1,AN); > oder > schalte(1,AUS); > > Den ganzen Kram mit den Arrays und Schnittstellenzuordnung brauchst du > dann nur einmal, eben in der Funktion schalte(geraetenummer,an_aus). das ist auch schick .. ICH würde aber die "1" durch eine pinter auf die gerätestruct ersetzen. geht sicherach benennung durch enum/defines ... aber das debuggt sich einfacher. zudem kann , wenn eh schon malloc/free verwendet wird ein konstructor - gebilde gebaut werden geraet_t *netzteil; netzteil = malloc ( sizeof( geraet_t )); Licht(netzteil , AN); oder durch fp* + macros.. netzteil->licht(1);
Vielen Dank für die Rückmeldungen. Der Aufruf selber ist eigentlich nicht das Problem. Mich würde interessieren, wie ich die UART und I²C-Schnittstelle gleichartig ansprechen kann. Ich habe schon eine struct, die einen Pointer auf den UART-Treiber enthält. Wenn ich jetzt einen I²C-Treiber über diese struct ansprechen will, müsste ich dafür auch einen entsprechenden Pointer einbinden und eine Variable zur Unterscheidung der jeweiligen Schnittstellensorte, oder? (Ich mache hier (im Forum) wohl gerade das Brainstorming, das ich eigentlich an meinem Schreibtisch machen sollte... ;) )
Gast
#4732773
jeder treiber hat eine struct mit fp* zu den passenden read/write/init/conf funktionen deine funktionen nutzen dann eben nur die struct
1 | |
wobei phy ein struct mit den fp der jeweiligen HW ist ob das nun I²C oder UART /SPI ist ... das musst du vorher eben festlegen
1 | |
2 | |
3 | |
Gast
#4757424
Eigentlich macht man das, indem man logische Devices (hier 1, mit 3 Instanzen) und physikalische erstellt und verbindet.
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
13 | |
14 | |
15 | |
16 | |
Alternativ zu LichtAn als Funktion kann es auch Memberfunktion sein die physikalischen Devices enthalten die Umsetzung, mit allgemeinen Funktionen oder quasi das phy-Pendant zu LichtAn. sphyUart.LichtAn() sendet z.B. "Befehl 37" raus. Es gibt dann je phy-Typ eine oder zwei Create und Initroutine, in denen der Speicher für den Treiber und z.B. Baudrate und Port mitgegeben werden (Uart): phyUSBA_a = CreateUart(usb_a, 9600, ...); Ebenso für die logischen Devices LKinderzimmer = CreateLampe(lampe1, ...); Zusätzlich gibt es je eine Verknüpfungsrouteine, die TLampe mit einem physikalischen Device verbindet. ConnectLampe_USB(TLampe L, TphyUSB USB); ConnectLampe_I2C(TLampe L, TphyI2C I2C); ConnectLampe_Uart(TLampe L, TphyUart Uart); Warum jeweils 3 Routinen? Weil es keine Gemeinsamkeiten gibt zwischen USB, I2C und Uart. Es macht 0 Sinn, die Obermenge zu abstrahieren und entsprechend kryptische Funktionen und Werteinterpretationen durch den Anwendercode zu ziehen. Man kann manchmal die Initialisierung des physikalischen Devices sparen und an die Connect_Funktion dranpappen. Ist aber meist nicht sinnvoll. Im Code hast Du nacher
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
bzw. mit Funktionspointern:
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
Moin moin, Achim S. schrieb: > Warum jeweils 3 Routinen? Weil es keine Gemeinsamkeiten gibt zwischen > USB, I2C und Uart. Naja, sowas kommt raus, wenn man nicht richtig nachdenkt ;) USB, I2C und Uart sind jeweils Frame-orientierte Übertragungsprotokolle. Ich sehe da schon Gemeinsamkeiten. Eine öffentliche Schnittstelle könnte so aussehen, dass man eine Adresse und die Daten für den Frame übergibt und eine Übertragungs-Funktion ausführt. Im Internen Bereich sind dann die Unterschiede versteckt. Das könnte man folgendermaßen umsetzen:
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
13 | |
14 | |
15 | |
16 | |
17 | |
18 | |
19 | |
20 | |
21 | |
22 | |
23 | |
24 | |
25 | |
26 | |
27 | |
28 | |
29 | |
30 | |
31 | |
32 | |
33 | |
34 | |
35 | |
36 | |
37 | |
38 | |
39 | |
40 | |
41 | |
42 | |
43 | |
44 | |
45 | |
46 | |
47 | |
48 | |
49 | |
50 | |
51 | |
52 | |
53 | |
54 | |
55 | |
56 | |
57 | |
58 | |
59 | |
60 | |
61 | |
62 | |
63 | |
64 | |
65 | |
66 | |
67 | |
68 | |
69 | |
70 | |
71 | |
72 | |
73 | |
74 | |
75 | |
76 | |
77 | |
78 | |
79 | |
80 | |
81 | |
82 | |
83 | |
84 | |
85 | |
86 | |
87 | |
88 | |
89 | |
90 | |
91 | |
Wer will könnte die Funktion schalte() auch durch ein Makro ersetzen (erspart einen Funktionsaufruf und Registersicherungen). Wenn die Funktionen der Kommunikations-Module öffentlich zugänglich sind, könnte man die Funktionszeiger in den commXX-Strukturen sparen (Platz) und die Zeiger in den Device-Strukturen direkt setzen.
Gast
#4774511
Reinhard M. schrieb: > USB, I2C und Uart sind jeweils Frame-orientierte Übertragungsprotokolle. Wie bitte? Du schreibst Unsinn. Beim UART hat man völlig asynchrone Einzelzeichen-Übertragung Beim I2C hat man adressierte Einzelzeichen-Übertragung (OpenSlave, Übertragung(en), CloseSlave) Beim USB hat man erstmal garnichts, sondern muß sich aus den Möglichkeiten, die USB so bietet, eine aussuchen und implementieren. Ob das nun Frame-orientiert ist oder nicht, isochron ist oder nicht und und und, hängt davon ab, was man da implementiert. Rahul D. schrieb: > Ich würde mir nun gerne eine Art Treiber scheiben (Keil C, RTOS u.a. > wegen USB-Host), der dafür sorgt, dass das übergeordnete Programm alle > Geräte gleich ansprechen kann. Ja, ist verständlich. > Wie realisiert man das? Etwa so:
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
So. So einen Struct kann man in den Flash legen. Der Typ muss einheitlich sein für alle Aktuatoren, die du so hast, egal ob so einer an einem UART oder I2C oder sonstwo dran hängt. Die allgemeinen daten im struct sollen allgemeingültig sein, also alles, was du so an allgemeinen und konstanten Daten benötigst. Für spezielle Daten, die sich auch ändern können, mußt du *Data benutzen. Der ist void, du mußt also dort in jedem Falle casten. Aber genau DAS machst du niemals in deinen übergeordneten Programmteilen, sondern NUR in deinen Treibern, die per OnInit oder OnMachwas oder so aufgerufen werden. Alle solche Treiber müssen das gleiche Interface haben, also die gleichen allgemeinen Parameter im Aufruf haben. Dazu kommt ein 'self', der auf den aktuellen struct zeigen muß. Zu jeder Interfaceart schreibst du dir nen Treiber. Das Entscheidende ist deren gleiches Interface zum aufrufenden Programm hin. Du hast also pro Gerät einen Struct im Flash. Dort stehen die nötigen Daten drin (z.B. Adresse oder Formatangaben für dessen Ansprechen) und es stehen die Funktionen drin, mit denen man das Gerät anspricht. Wenn variable Daten benötigt werden, bekommt jeder Struct einen eigenen Bereich im RAM, wo *Data hinzeigt. W.S.
>> USB, I2C und Uart sind jeweils Frame-orientierte Übertragungsprotokolle. > > Wie bitte? > > Du schreibst Unsinn. Ja, war klar :) Kommt eben drauf an, ob man Gemeinsamkeiten finden will, oder nicht. Ich hatte den TE so verstanden, dass er nach Gemeinsamkeiten suchte und zugleich seinen Code leserlicher machen wollte. Wenn ich mir die Protokolle aus Anwendersicht anschaue, dann kann ich mit jedem mehrere Clients ansprechen. Brauche also irgendetwas, um die Clients zu unterscheiden. Üblicherweise nennt man das Adresse Dann will ich dem Client ja auch was mitteilen, in diesem konkreten Fall eben "einschalten". Dafür würde ein Bit ausreichen. Mir ist aber nicht bekannt, dass die Protokolle die Übertragung eines einzigen Bittes unterstützen würden. Also muss man das Bit bis zur Mindestübertragungsgröße auffüllen. Manchmal ist es ein Byte, kann aber auch mehr oder weniger sein. Deshalb sprach ich von Frames. Ein Frame ist einfach eine feste Anzahl an Bits, die mich als Anwender aber garnicht interessieren muss ;) Wie auch immer, ich würde das, was ich dem Client mitteilen will als Nutzdaten (bezogen auf die Übertragung) bezeichnen. Also sind wir genau bei dem von mir modellierten Ansatz. Wenn es eine reine Master-Slave-Verbindung ist, könnte man den Lese-Kanal sogar weglassen. Man könnte auch noch weitere Übertragungsprotokolle wie Ethernet oder SPI zufügen ohne an dem Konzept irgendwas ändern zu müssen. Aber wie gesagt: diese Sichtweise muss man auch wollen :) Was mir bei Deinem Konzept nicht einleuchtet: wieso soll ich Platz für vier Funktionszeiger verschwenden, wenn einer dafür ausreicht?
Gast
#4775742
Nana, DU bist doch garnicht der TO. De wollte seine diversen Aktuatoren trotz höchst unterschiedlicher HW auf gleiche Weise behandeln können. Und wenn dir ein Beispiel namens OnMachwas(...) nicht von selbst einleuchtet, dann sei's dir erklärt: Das ist ein Beispiel. Man braucht nicht vier Funktionspointer, sondern eben so viele, wie man im konkreten Fall eben braucht - genauso geht's mit eventuellen konstanten Daten und/oder Variablen. Aber das ist Sache des TO. Nochwas: Wenn dir schon klar war, daß du Unsinn schreibst, warum tatest du es? Frame-orientierte Übertragungsprotokolle sind solche, die eben einen Frame, also einen Rahmen haben. Ethernet-Pakete zum Beispiel. Aber ein asynchron gesendetes Zeichen auf einer seriellen Schnittstelle gehört nicht dazu. Es ist eben nur ein Zeichen und sonst nix. W.S.
W.S. schrieb: > De wollte seine diversen Aktuatoren trotz höchst unterschiedlicher > HW auf gleiche Weise behandeln können. Wollte er dies nicht, so bräuchte er kein OOP. > Man braucht nicht vier Funktionspointer, sondern eben so viele, > wie man im konkreten Fall eben braucht Du kannst einen Aktuator als "kann links(), rechts(), oben(), unten() und stop() ausführen" betrachten. Du kannst einen Aktuator aber auch als "verarbeitet Bytesequenzen nach Protokoll XY" betrachten. Im ersten Fall ist dein Ansatz sinnvoller. Im zweiten Fall ist Reinhards Ansatz sinnvoller. Per se Unsinn ist keiner der Ansätze. > Frame-orientierte Übertragungsprotokolle sind solche, die eben > einen Frame, also einen Rahmen haben. "A frame typically includes frame synchronization features consisting of a sequence of bits or symbols that indicate to the receiver the beginning and end of the payload data within the stream of symbols or bits it receives." (Wikipedia) In meiner naiven Weltsicht erfüllt die Übertragungseinheit einer seriellen Schnittstelle (also Startbit, Datenbits, Paritätsbit und Stopbits) diese Anforderungen. Und um Reinhard zu zitieren: >> Kommt eben drauf an, ob man Gemeinsamkeiten finden will, oder nicht. Du willst offensichtlich keine Gemeinsamkeiten finden. Deine Entscheidung. > Aber ein asynchron gesendetes Zeichen auf einer seriellen Schnittstelle > gehört nicht dazu. Es ist eben nur ein Zeichen und sonst nix. Das Zeichen ist der Payload. Davor und dahinter sind aber auch wichtige Bits.
Gast
#4776990
S. R. schrieb: > In meiner naiven Weltsicht erfüllt die Übertragungseinheit einer > seriellen Schnittstelle Ach, frag dich doch erstmal, ob der TO von solcher Sophisterei einen Nutzen hätte. Ich bezweifle dies. Und hier geht es auch nicht darum, was Reinhard fokussiert: Reinhard M. schrieb: > USB, I2C und Uart sind jeweils Frame-orientierte Übertragungsprotokolle. > Ich sehe da schon Gemeinsamkeiten. Eine öffentliche Schnittstelle könnte > so aussehen, dass man.. Nein, Eben genau das ist eigentlich egal. Dem TO ging es nicht darum, Gemeinsamkeiten diverser Peripheriecores und deren Verhalten zu finden, sondern er will seine Aktuatoren (O-Ton: "verschiedene gleichartige Geräte") unabhängig von deren Anbindung auf gleiche Weise ansprechen. Nochmal zum Mitschreiben: Die Geräte sind das Ziel und nicht die Strippe zu ihnen. Deshalb soll es für das Ansprechen herzlich wurscht sein, ob das eine am I2C und das nächste am USB-OTG oder sonstwo dran hängt. Ich hab ihm eine Art Quasi-Objekt-Lösung vorgeschlagen, wo die Unterschiede in der Art der "Strippe" im jeweiligen Objekt gehandhabt werden und das Interface zum aufrufenden Programm hardwareunabhängig ist. Klaro? W.S.
Gast
#4777474
Reinhard M. schrieb: > Kommt eben drauf an, ob man Gemeinsamkeiten finden will, oder nicht. > Ich hatte den TE so verstanden, dass er nach Gemeinsamkeiten suchte und > zugleich seinen Code leserlicher machen wollte. Das klappt aber bei Dir nicht. Vermutlich hast Du meinen Post entweder nicht gelesen oder nicht verstanden, ebenso nicht die Ausführungen von W.S. Bei Deinem Bemühen, Gemeinsamkeiten zu finden, verlagerst Du A)Implementierungsdetails der Device-Treiber in die abstrakte Lampenebene. Reinhard M. schrieb: > Device LampeKinderzimmer = { > .address = LAMPE_KINDERZIMMER, > .onCommand = USB_EIN, > .offCommand = USB_AUS, > .send = commUSB.send, > .receive = commUSB.receive, > .commInfo = &commUSB > }; und legst Dir Beschränkungen bei der Implementierung auf, um künstlich "Gemeinsamkeiten" zu beschwören. W.S.: (oder mein Beispiel) trennt die Logische Ebene (Lampen schalten) komplett den Device-Treibern. Falls es Gemeinsamkeiten gibt, spricht ja nichts dagegen, die aus einer gemeinsamen Basis zu bedienen, auf keinen Fall aber über die Lampenebene. Wenn Du solche Device-Treiber mal wirklich selbst durchdenkst (von A bis O), dann wirst Du das folgende früher oder später selbst erkennen: Achim S. schrieb: > Warum jeweils 3 Routinen? Weil es keine Gemeinsamkeiten gibt zwischen > USB, I2C und Uart. Es macht 0 Sinn, die Obermenge zu abstrahieren und > entsprechend kryptische Funktionen und Werteinterpretationen durch den > Anwendercode zu ziehen. Explizit nochmal zu Deiner Frage: Reinhard M. schrieb: > wieso soll ich Platz für > vier Funktionszeiger verschwenden, wenn einer dafür ausreicht? Weil die 4 Funktionszeiger in dem Beispiel sehr les- und handhabbar sind. Wenn dem Designer 1 Funktionszeiger lieber ist, macht er nur eine Funktion "DoCommand(..., int cmd, ...)" mit festgelegten Kommandos. Aber genau nicht auf Datenebene der Devicetreiber, sondern abstrakt dazu, z.B. 1=Init, 2=An, 3=Aus, 4=Toggle,....)
> Das klappt aber bei Dir nicht. Nur weil ich es anders als Du mache, heißt es noch lange nicht, dass es nicht klappt. > Bei Deinem Bemühen, Gemeinsamkeiten zu finden, verlagerst Du > A)Implementierungsdetails der Device-Treiber in die abstrakte > Lampenebene. Naja - ich habe die Abstraktion eben anders aufgeteilt. Nicht streng religiös nach Schichten, sondern nach Initialisierung und Aufruf. Der TE schrieb ja, dass sich eine Lampe (ein device) in Adresse und Kommunikationskanal unterscheiden kann. Ich habe dann einfach die Flexibilität etwas erhöht und angenommen, dass sich auch die Nutzdaten je nach Kommunikationskanal ändern könnnten. Deshalb habe ich die Variable mit in die Struktur aufgenommen. Wenn diese Flexibilität nicht gebraucht wird, kann man die Variable auch einfach wieder entsorgen :D Bei der Initialisierung der Struktur muss/sollte man wissen, welche Kommunikationsart verwendet wird. Aber nur da. Bei der Verwendung der Strukturen ist es völlig transparent, welche Kommunikationsart, -adresse und -befehl verwendet werden. Das ist in der Struktur versteckt. Somit können beliebig viele devices unterschiedlichster Art über ein und das selbe Array und die jeweils gleiche Funktion angesprochen werden. Das ist jetzt nicht OO nach C++ sondern eben reines C. Also genau das, was der TE wünschte. Wenn mein Vorschlag mit irgendeiner Abstraktionsphilosophie nicht harmoniert, dann ist mir das völlig schnuppe. Die Lösung funktioniert. Ob sie den Anforderungen entspricht, kann eigentlich nur der TE entscheiden :)
Gast
#4778156
Reinhard M. schrieb: > Naja - ich habe die Abstraktion eben anders aufgeteilt. Nein, du hast es noch immer nicht begriffen. Natürlich kann man immer mit dem Argument kommen, daß es ja auch anders ginge. Stimmt, in Assembler kann man alles - nur so als Beispiel. Aber das ist hier kein wirkliches Argument. Mal ganz vom hohen Roß aus gesprochen: Objektorientierte Programmierung besteht darin, daß man Objekte hat, die nach außen hin, also in Richtung der übergeordneten Programmschichten, sich gleich verhalten, obwohl sie im Inneren höchst unterschiedlich sein können. Dazu haben sie alle einen Satz von Methoden und allgemeinen Eigenschaften, die auf alle Objekte zutreffen - obwohl sie im Inneren sowohl unterschiedliche weitere Eigenschaften haben können als auch im Inneren der äußerlich gleichen Methoden die Luzie von einem Objekt zum anderen ganz unterschiedlich abgeht. Lehrbeispiel sind grafische Elemente auf einem Programmfenster: Selbiges sagt nur "For All My Elements: Draw_Yourself();" und es ist dem Fenster egal, ob das nun ein Punkt, eine Linie, Dreieck, Kreis oder Kringel ist. Im Inneren dieser Objekte sind unterschiedliche Zeichenmethoden vorhanden, denn ein Kreis zeichnet sich anders als ein Dreieck. Aber gegenüber dem Fenster sind sie alle gleich. Nun klaro? W.S.
Konkretes Beispiel: HD44780-Display, angeschlossen per SPI, I2C oder GPIO. Dein Ansatz: Ich schreibe drei Treiber, DP_SPI, DP_I2C, DP_GPIO, die jeweils eine Methode PrintString() besitzen. Mein Ansatz: Ich schreibe drei Treiber, BUS_SPI, BUS_I2C, BUS_GPIO, die jeweils eine Read()- und eine Write()-Methode haben, und einen Treiber DP, der eine Methode PrintString() hat. Welcher Ansatz ist immer und ausnahmslos besser?
S. R. schrieb: > Welcher Ansatz ist immer und ausnahmslos besser? Das Wichtigste ist eben: Reinhard M. schrieb: > Das ist jetzt nicht OO nach C++ sondern eben reines C. ;-)
> Welcher Ansatz ist immer und ausnahmslos besser? Keine Ahnung. Wen interessierts? Ich verwende C nur für die kleinen AVRs - und dabei ist mir ein Kompromiss zwischen lesbarem Code, Codegröße und Ausführungsgeschwindigkeit wichtig. Mir ist nicht wichtig, dass mir ein Theoretiker über den Kopf streicht und meint: haste gut gemacht. Wenn er die Nase rümpft und meint: was soll der Chice - tja, vielleicht hat er dann ja nicht verstanden, worauf es ankommt? Für mich zählen die 3 genannten Eckpunkte. Bei größeren Prozessoren greife ich dann schon zu C++ - da wird dann auch anders modelliert. Das kostet aber viel Speicher und Laufzeit gegenüber der C-Variante. Also muss ich bereit sein, die Nachteile für eine sauberere Kapselung in Kauf zu nehmen. Sich in C die Nachteile von C++ anzutun, ohne von irgendwelchen Vorteilen zu profitieren, ist für mich nicht erstrebenswert ;)
Gast
#4778682
S. R. schrieb: > Welcher Ansatz ist immer und ausnahmslos besser? Natürlich der zweite Ansatz. Der spräche auf den ersten Blick für Reinhard (mehr im Aufrufer zentralisieren). M.E. hinkt der Vergleich hier aber, da Reinhard nicht nur Printf (da stimme ich zu), sondern (um im Beispiel zu bleiben) auch Display-Kommandos und Schnittstellen-internas zum Aufrufer verlagert (das lehne ich ab).
Reinhard M. schrieb: > Device LampeKinderzimmer = { > .address = LAMPE_KINDERZIMMER, > .onCommand = USB_EIN, > .offCommand = USB_AUS, > .send = commUSB.send, > .receive = commUSB.receive, > .commInfo = &commUSB > }; So etwas hat in der Firmware einer Steuerung nichts zu suchen. Das sind Konfigurationsdaten, die man am besten im Konfigurationsgerät (PC, Smartphone öä) speichert. In die Firmware gehören universelle Geräte, die man von außen konfigurieren kann. Sonst muss man ja für jede Änderung, für jedes neue Gerät, den µC neu programmieren. Und wenn der Nachbar oder Schwager auch so etwas will,fängt man nochmal von vorne an.
> So etwas hat in der Firmware einer Steuerung nichts zu suchen. Das sind > Konfigurationsdaten, die man am besten im Konfigurationsgerät (PC, > Smartphone öä) speichert. Ok, dann habe ich wohl was falsch verstanden. Ich bin davon ausgegangen, dass der Master auch ein µC mit Firmware wäre und dass es um die Programmierung der Master-Seite geht. Für die Treiberseite ist das was ich geschrieben habe, natürlich Kwatsch mit Source =:O Das würde ich auf Client-Seite nie so machen. Ich hatte die Clientseite auch nie im Blickfeld. Wenn das gefordert war, dann bitte ich alle meine Beiträge zu ignorieren ;) Wenn die Steuerung die Intelligenz hat, sich Konfigurationsdaten von außen rein zu ziehen, dann kann man die Feilder .adress, .onCommand und .offCommand auch nachträglich überschreiben. Wo ist das Problem? > und Schnittstellen-internas zum Aufrufer verlagert (das lehne ich ab). Davon kann keine Rede sein. Bitte meine Beiträge nochmal anschauen. Es ging nicht darum, Schnittstellen-Internas zum Aufrufer hoch zu ziehen, sondern die Flexibilität zu haben, wenn ein Client per USB eine andere Befehlssequenz braucht, als per I2S, dass man das dann eben mit abbilden kann. ... und zwar so, dass der Aufrufer (also der Benutzer der Struktur) nix davon mitbekommen muss. Von den Schnittstellen-Internas will ich ganz sicher nix zum Aufrufer hoch ziehen.
Antwort schreiben
Bitte melde dich an, um einen Beitrag zu schreiben.