Hallo zusammen,
ich bin heute über die list.h & types.h (Linux) gestolpert und die
Funktionalität der
1
structlist_head
ist genau das was ich gesucht habe.
Nun würde ich dies gern in meinem Projekt nutzen - Cortex-M4(Atmel).
Darf ich mir nun den Spaß machen und alle include Abhängigkeiten selbst
auflösen (Dateien kopieren, ...).
Dazu kommen natürlich dann auch noch die arch include usw.
Oder gibt es da einen einfacheren Weg?
Ich möchte keine andere lib nutzen die das auch könnte, sonder schon den
Linux source.
Klar, oder selbst nachschreiben...
jedoch, wozu das Rad neu erfinden.
Gruß
Adam P. schrieb:> Oder gibt es da einen einfacheren Weg?> Ich möchte keine andere lib nutzen die das auch könnte, sonder schon den> Linux source.
Aber warum? Im Internet gibt es Tausende Implementationen von
verketteten Listen. Man kann sie auch recht einfach selbst
implementieren. Oder C++ verwenden, was bereits eine Liste eingebaut hat
(std::list).
Niklas Gürtler schrieb:> Adam P. schrieb:>> Weil es sich bewährt hat?>> Das haben andere Bibliotheken auch...
OK, bin ja immer offen für neues. Hast du mir eine Bsp.-Lib?
edit:
Ich greife aus Interesse für Neues erst zum Linux source.
c++-hater.. schrieb:>> Geht nicht.> Sehr vernünftig!
Hast du eine Idee @c++-hater?
Anscheinend bleibt wohl nichts übrig als einen eigenen Port zu basteln,
oder?
edit:
Gerade mit einem Kollegen tel. und er meinte auch, das er sowas schon
oft brauchte, aber es nie fertig zum nutzen gab, wenn man kein Linux
nutzt.
Adam P. schrieb:> OK, bin ja immer offen für neues. Hast du mir eine Bsp.-Lib?
Hier eine Auswahl:
https://github.com/oz123/awesome-c#data-structuresAdam P. schrieb:> Das offsetof() habe ich im arm-gcc compiler.h
offsetof ist ein Standard-Makro und in <stddef.h> definiert, wozu
braucht es da noch arm-gcc-compiler.h ?
Adam P. schrieb:> Niklas Gürtler schrieb:>>> Oder C++ verwenden>> Geht nicht.
Aha... Datenstrukturen lassen sich in C++ sehr viel eleganter und
sicherer implementieren.
Aber noch eine ganz andere Frage: Machen verkettete Listen und die damit
meistens einhergehende dynamische Speicherverwaltung auf
Mikrocontrollern Sinn? Ich komme meistens mit Arrays, Ringpuffern oder
o.ä. aus.
Niklas Gürtler schrieb:> offsetof ist ein Standard-Makro und in <stddef.h> definiert, wozu> braucht es da noch arm-gcc-compiler.h ?
Sorry hatte mich vertan, natürlich meine ich die stddef.
Zu viele Header angeschaut und durcheinander gekommen.
Niklas Gürtler schrieb:> Aber noch eine ganz andere Frage: Machen verkettete Listen und die damit> meistens einhergehende dynamische Speicherverwaltung auf> Mikrocontrollern Sinn? Ich komme meistens mit Arrays, Ringpuffern oder> o.ä. aus.
Da magst du recht haben, habe das bis jetzt auch so gemacht.
Jedoch haben die Listen den Vorteil, dass man kein RAM verschwendet.
Bsp.:
Ich habe ein CLI (command line interface) Modul.
Andere Module können nun ihre Funktionen dort registrieren,
dafür besitzt das CLI Modul ein struct Array in dem die Callback
Funktionen und der String abgelegt wird.
1
#define CLI_MAX_CMD_LENGTH 15
2
#define CLI_MAX_CMD_COUNT 50
3
4
typedefstruct
5
{
6
charcmd[CLI_MAX_CMD_LENGTH];
7
cli_funcfunc;
8
}cli_cmd_t;
9
10
staticcli_cmd_tcli_cmd[CLI_MAX_CMD_COUNT];
Registriere ich nun nur 3 Funktionen, müsste ich das define anpassen um
nicht unnötig RAM freizuhalten.
Würde man dies auf Listen umbauen, dann würde sich das Problem in Luft
auflösen.
Adam P. schrieb:> Jedoch haben die Listen den Vorteil, dass man kein RAM verschwendet.
Der Punkt ist - für gesparten RAM gibt es kein Geld zurück. Auf einem uC
ohne OS kann schließlich kein anderes Programm laufen und den freien RAM
nutzen, wie auf dem PC. Daher ist es für uC-Programme völlig legitim,
den maximal benötigten RAM statisch zu allokieren.
Adam P. schrieb:> Bsp.:> Ich habe ein CLI (command line interface) Modul.> Andere Module können nun ihre Funktionen dort registrieren,
Warum ist das überhaupt im RAM? Das ändert sich doch nicht. Warum nicht
ein konstantes Array im Flash mit allen Funktionen? Du brauchst halt an
zentraler Stelle einmal eine Auflistung aller Module bzw. der
Funktionen. Die brauchst du aber sowieso, weil du die Module ja auch
starten können musst.
Niklas Gürtler schrieb:> Daher ist es für uC-Programme völlig legitim,> den maximal benötigten RAM statisch zu allokieren.
Schon, jedoch geht es eher darum, RAM nicht zu verschwenden,
da dieser bekanntlich nicht im Bereich MB oder GB liegt sondern in
meinem Fall nur 128K beträgt.
Auf meinem System A alles kein Problem, das System B hat jedoch noch ein
OLED und da wird es sehr eng - Optimierungen wären da sehr hilfreich.
Niklas Gürtler schrieb:> Warum ist das überhaupt im RAM? Das ändert sich doch nicht. Warum nicht> ein konstantes Array im Flash mit allen Funktionen? Du brauchst halt an> zentraler Stelle einmal eine Auflistung aller Module bzw. der> Funktionen. Die brauchst du aber sowieso, weil du die Module ja auch> starten können musst.
Da ich es als Blackbox betrachten möchte.
Jedes Modul kann es nutzen oder auch nicht, Anpassungen/Änderungen am
CLI Modul selbst sind dann nicht notwendig.
Das Zephyr OS erfreut sich wachsender Beliebtheit, ist von der Linux
Foundation und macht wohl einiges wie Linux. Habe es selber noch nicht
benutzt weil ich C++ lieber mag, aber linked lists sind da auch
vorhanden.
Adam P. schrieb:> Jedoch haben die Listen den Vorteil, dass man kein RAM verschwendet.
Hm? Zunächst braucht jedes Listenelement einen zusätzlichen Zeiger auf
seinen Nachfolger, und falls doppelt verkettet nötig ist, auch auf den
Vorgänger. Dazu kommt, dass dann jedes Listenelement einzeln dynamisch
allokiert wird und damit zusätzlichen Overhead für die internen
Verwaltungsdaten des Speichermanagers hat (meist nochmal mindestens ein
Zeiger).
> Registriere ich nun nur 3 Funktionen, müsste ich das define anpassen um> nicht unnötig RAM freizuhalten.>> Würde man dies auf Listen umbauen, dann würde sich das Problem in Luft> auflösen.
Was du dafür brauchst, ist dynamischer Speicher. Der geht auch ohne
verkettete Listen.
Adam P. schrieb:> Da ich es als Blackbox betrachten möchte.> Jedes Modul kann es nutzen oder auch nicht, Anpassungen/Änderungen am> CLI Modul selbst sind dann nicht notwendig.
Speicherplatz sparen zu wollen, passt aber nicht wirklich damit
zusammen, dann die Registrierung von Modulen, die zur Compilezeit alle
bekannt sind, erst dynamisch zur Laufzeit durchzuführen. Das erhöht
nämlich den Bedarf an RAM und braucht auch zusätzlich flash, weil dafür
ja auch zusätzlicher Code nötig ist.
Adam P. schrieb:> Schon, jedoch geht es eher darum, RAM nicht zu verschwenden,
Du möchtest RAM sparen, aber dann...
Adam P. schrieb:> Da ich es als Blackbox betrachten möchte.> Jedes Modul kann es nutzen oder auch nicht, Anpassungen/Änderungen am> CLI Modul selbst sind dann nicht notwendig.
Bei cleverer Programmierung geht auch das. Wenn du ein konstantes Array
von Modulen hast, kann das CLI Modul zur Suche von Befehlen alle Module
iterieren, und jedes Modul hat wieder ein statisches Array aus Befehlen,
die einfach iteriert werden können (2 Schleifen ineinander). Das braucht
dann überhaupt keinen RAM, fährt schnell hoch, und das Iterieren ist
auch schneller.
Adam P. schrieb:> Schon, jedoch geht es eher darum, RAM nicht zu verschwenden,> da dieser bekanntlich nicht im Bereich MB oder GB liegt sondern in> meinem Fall nur 128K beträgt.>> Auf meinem System A alles kein Problem, das System B hat jedoch noch ein> OLED und da wird es sehr eng - Optimierungen wären da sehr hilfreich.
Je nun, wenn du mehr Listenelemente benötigst, als ins Ram passen, dann
benötigst du mehr Listenelemente, als ins Ram passen. Beim statischen
Ansatz mit festem Array findest du das (mit etwas Vorsorge) schon zur
Compilezeit raus, mit dynamischen Listen gibt das einen Fehlerfall, der
zur Laufzeit abgefangen werden muß. Ob man das auf einem Microcontroller
will oder überhaupt sinnvoll kann, ist deine Entscheidung. Wenn das
letzte Listenelement noch passt, dann aber der OLED-Code wegen
Speichermangel crasht, wirds kompliziert.
Oliver
Eine zentrale Komponente braucht's doch auch so oder so. Schließlich
muss die Registrierfunktion aller Module ja auch von irgendwo aufgerufen
werden. Wenn man jetzt stattdessen an dieser Stelle eine statische
Tabelle der zu registrierenden Funktionen anlegt, die dann von deinem
CLI als input genutzt wird, kann man sich die Registriererei zur
Laufzeit sparen.
Die redundante Größenangabe des Module-Arrays mittels Makro-Magic
wegzuoptimieren sei als Übung überlassen :)
So entfällt die Initialisierung komplett und es wird überhaupt kein RAM
benötigt. Externe Abhängigkeiten hat man sich auch gespart, und das
hässliche offsetof() ebenfalls.