Archiv verlassen und diese Seite im Standarddesign anzeigen : C++ fstream GPIO Trigger/Interrupt
alexander_ro
14.01.2018, 11:11
Hi Mädels ... Jungs ... :)
Ich baue mir gerade eine C++ Klasse für den Raspberry um einfacher mit den GPIO arbeiten zu können. Das konfigurieren und je nachdem ob Out/In kann ich den GPIO auch lesen und schreiben. Nur den als Trigger zum Auslösen von Funktionen zu benutzen habe ich Probleme. Die meisten anderen benutzen nicht fstream dafür was meiner Meinung nach Grund genug ist den zu benutzen oder es zumindest mal zu probieren. :)
Hier ist die Klasse zu finden: https://git.hts-software.de/index.html/Athena-Api/tree/Gpio/Gpio.hpp in der Funktion checkTrigger ist ein unvollständiges Beispiel mit poll.
Um aber einen GPIO als Trigger zu benutzen muss man überwachen ob dieser sich verändert. Normal macht man das mit z.B. poll, epoll. Der benötigt aber leider den Filedeskriptor den ich bei einem fstream ja nicht habe. Ich vermute mal das auch ein fstream eine Möglichkeit hat um abzufragen ob sich dieser verändert hat. Leider habe ich das auch nach längerer suche nicht gefunden. Man findet da irgendwie immer nur die C Lösung mit poll oder besser epoll.
Grüße
Alexander
schorsch_76
15.01.2018, 08:57
Hallo Alexander,
ich würde die Datei einfach mit open() öffnen. Auf den GPIO schreibst du ja keine Datei sondern nur mal 1/0. Dann geht auch epoll/select/poll.
Siehe zur Konvertierung OStream->file descriptor
https://gcc.gnu.org/ml/libstdc++/2000-q1/msg00049.html
> So will the new libstdc++ provide such a way?
If you compile the current CVS libstdc++ with _STREAM_COMPAT, you get
a filedesc() method on an fstream object, returning the file
descriptor. Alternatively, you can use fstream::rdbuf()->fd()
(which filedesc() is a short-hand for).
Regards,
Martin
Vielleicht hat ja die aktuelle libstdc++ diese Methode da der Post von ca 2000 ist, muss das nicht mehr stimmen.
Gruß
Georg
- - - Aktualisiert - - -
Siehe auch https://www.ginac.de/~kreckel/fileno/
alexander_ro
15.01.2018, 11:19
Mit open und poll/epoll weiß ich ja wie es geht. Deshalb mal der Versuch es anders zu machen. Bei solchen Experimenten sind schon manches mal erstaunliche Dinge entdeckt worden.
Das erste hatte ich auch schon gefunden geht aber leider nicht:
../Gpio.hpp:117:55: Fehler: »std::basic_fstream<char>::__filebuf_type {aka class std::basic_filebuf<char>}« has no member named »fd«
pollIntPort.fd = fileIntPortValue.rdbuf()->fd();
Das zweite müsste ich mal probieren es sieht aber ein bisschen merkwürdig aus.
Eigentlich dachte ich würde ein fstream das können aber scheinbar halten das die Macher der Standards für nicht wichtig das ein Programm über die Ankunft neuer Daten in Kenntnis gesetzt wird. Merkwürdig ...
Vielleicht gibt es ja den Weg anders herum das ich zuerst mit open das File öffnen und dann den Deskriptor einem fstream übergebe. Oder so ähnlich ...
Also nicht wirklich was ich mir vorstelle aber der Theorie nach kann man zum lesen Dateien ja auch mehrfach öffnen. Dann könnte man einfach schreiben und Daten lesen über den fstream und das überwachen für den Trigger mit open und epoll. Auch nicht wirkllich gut die Idee ... :(
Ich würde vorschlagen, dass man sich die Arbeit spart selbst eine GPIO implementierung für den Pi zu schreiben und stattdessen WiringPi verwenden. Das kann auch die Sache mit den Interrupts (http://wiringpi.com/reference/priority-interrupts-and-threads/). Jetzt kann man sagen: ohh ok das verwendet ja einen Thread um den Zustand im Hintergrund zu pollen. Ja das stimmt. Wenn man sich aber mal anschaut wie so ein GPIO Interrupt implementiert werden kann ist das aber auch nicht tragisch. Für Interrupts gibt es prinzipiell zwei Möglichkeiten wenn man das mal aus der HighLevel Ebene von der wir kommen betrachtet. Die Erste ist: Die Hardware merkt, der Pin Zustand hat sich geändert und unterbricht des Datenfluss der CPU und springt dafür an eine hinterlegte Interrupt Addresse. Die Zweite ist: Naja dein Betriebssystem tut so als ob es ein Hardwareinterrupt ist, nimmt dir aber nur das Polling ab. Ich vermute stark dass die zweite Variante beim Raspberry verwendet ist (Ohne Garantie). Allein aus Sicherheitsgründen als auch dass die Implementierung einfacher ist.
Ob jetzt aber das Betriebssystem für dich Pollt oder du selber (Was WiringPi macht) ist letztendlich egal (auch mit Einschränkungen - weil das Betriebssystem kann das unter Umständen besser. Deshalb meine Empfehlung: Erfinde das Rad nicht neu und verwende WiringPi dafür.
Um dein Vorgehen aber auch noch zu diskutieren. Zum einen solltest du wissen, das Dateisystem unter /proc (wo man hintschreibt um die GPIOs zu steuern) ist nur ein virtuelles Filesystem. D.h. eigentlich wird im Hintergrund ein Syscall des Kernels aufgerufen und irgendwas gemacht. Das gleiche gilt auch fürs Lesen. Da müsste man sowie so erst mal Recherchieren ob man das überhaupt mit den normalen Methoden die es gibt um eine Änderungen des FIles mitzubekommen funktioniert (Mein Tipp wäre ja).
Bezüglich deines Filedescriptors: Mein Vorschlag wäre: Nimm direkt die C API (also open()). Das wäre zumindest der schöne weg.
Wenn du unbedingt fstream verwenden willst ist vermutlich das hier deine Rettung: http://www.cpptips.com/fstream
Ich würde dabei auch darauf achten, dass ich für C++11 und nicht C++98 kompiliere.
TLDR ;) Nimm WiringPi und leb damit dass es dort in einem Thread gepollt wird. Ansonsten -> Nimm die C Api
EDIT. Zum Thema: Die Macher des Standards halten etwas nicht für wichtig. Doch das tun sie, aber sie achten noch wesentlich mehr darauf dass es Plattform übergreifend funktioniert
EDIT2: Wenn ich mir WiringPi noch mal anschaue: Vllt pollen die noch nicht mal sondern verwenden den System interrupt
EDIT3: Schau dir eventuell auch die filesystem Erweiterung aus C++17 an: http://en.cppreference.com/w/cpp/experimental/fs
(http://en.cppreference.com/w/cpp/experimental/fs)
alexander_ro
15.01.2018, 13:38
WiringPi ist meines Wissens C und eher weniger C++ auch wenn C vollständiger Sprachbestandteil von C++ ist.
Das Rad neu erfinden in dem Sinn würde ich nur wenn ich das in C und Funktionsbasiert machen würde wie eben WiringPi es macht.
Ob man aus dem User Space oder Kernel Space pollt ... der Unterschied könnte nicht größer sein. Wenn stimmt was geschrieben steht ist epoll die schnellste Variante und eine Kernel Schnittstelle. Das ich es jetzt anders zu machen versuche ist nicht unbedingt Performance mein erstes Ziel. Sondern nicht Funktions- sondern Objektorientier programmieren die Klassen leicht anwendbar zu machen und Fehlertoleranz, Fehleranalyse und Fehlerhandling besser zu machen.
Über das proc fs die GPIO zu konfigurieren und zu benutzen ist nicht die schnellste Version aber aus Kernel sicht vollkommen in Ordnung. Ein Unix Grundsatz wenn nicht vielleicht sogar einer der wichtigsten alles ist eine Datei und genau auf diese weiße anzusprechen. Memory Mapped IO wäre die schnellste Version ... auch wieder wenn es stimmt was geschrieben steht. Ich habe es bisher nicht ausprobiert. Man spart sich hier den Filesystem Overhead.
"Das wäre zumindest der schöne weg." => Das wäre der übliche Weg ... darauf können wir uns einigen.
Compiler Option c++11 benutze ich im Moment.
Von der Architektur her sehe ich nicht wirklich einen Unterschied zwischen der C API und WireingPi.
http://www.cpptips.com/fstream Das ist das gleiche wie der erste Vorschlag vom schorsch_76.
Wie bereits oben geschrieben funktioniert das bei mir nicht. Soweit mir bekannt haben die libc++ Entwickler alles nicht Standardkonforme entfernt was eigentlich sehr löblich ist.
Zum Standard muss ich sagen ich bin mir zwar nicht ganz sicher aber relativ ... jedes Moderne Betriebsystem unterstützt solche Sachen wie poll auf die eine oder andere Art. Das glaube ich ist nicht der Grund warum es nicht vorhanden ist. Den Streams konnte man vor c++11 nur char* als Dateinamen übergeben ich hatte nie verstanden warum nicht auch einen std::string. Kaum wartet man einige Jahre und schon gibt es c++11 und man darf auch std::string übergeben ... ;)
Ja stimmt das mit dem filesystem aus c++17 sollte ich mir anschauen. Wollte ich auch schon aber immer wieder vergessen ... :(
soweit ich weiß, ist Linux (samt Kernel-Funktionen) in C geschrieben, nicht in C++, und der kernel besitzt ja die GPIOs - aber ich bin da absolut kein Fachmann.
Wenn es dir nur darum geht, im Userspace auf GPIOs zuzugreifen, würde ich shedepe in jedem Falle Recht geben, dass das mit wiringPi sehr einfach und failsafe möglich ist.
Wenn du aber schnellere Funktionen, die direkt den kernel nutzen, verwenden möchtest, wäre auch pigpio eine sehr gute Quelle, denn sie sind großenteils noch deutlich schneller als die von wiringPi.
Ich selber verwende pigpio nicht, mir langt die wiringPi Performance, aber wenn du im RaspberryPi.org Forum nachfragst,
https://www.raspberrypi.org/forums/viewforum.php?f=33&sid=c3510c309cae6a9e3a832e3a42a7309e
wirst du sicher sehr schnell sehr professionelle Hilfe bekommen: denn hier sind auch die Original-Autoren der beiden Libs (Henderson, Joan) sowie Mitarbeiter und Entwickler des Pis präsent und werden dir möglicherweise direkt antworten.
alexander_ro
15.01.2018, 18:32
Stimmt schon das der Kernel in C geschrieben wird. Soll das nun heißen das deshalb jeder der unter Linux Software schreibt das auch in C tun muss?
Das ich es nicht mache wegen der Performance habe ich ja vorher schon mal geschrieben. Ich will ein C++ Objekt haben das die GPIO Funktionen steuert. Klar kann ich ein Objekt um die WiringPi basteln aber Zwiebel Software ist auch nicht so mein Ding wenn ich nicht muss versuche ich zu vermeiden das ich eine Schicht um die nächste Hülle.
In dem Raspiforum finde ich auch nur poll dafür. Die werden nicht anders reagieren als hier und nicht beim Problem helfen wollen sondern mir einreden wollen das ich es machen soll wie es alle machen.
Stimmt schon das der Kernel in C geschrieben wird. Soll das nun heißen das deshalb jeder der unter Linux Software schreibt das auch in C tun muss?
...
In dem Raspiforum finde ich auch nur poll dafür. Die werden nicht anders reagieren als hier und nicht beim Problem helfen wollen sondern mir einreden wollen das ich es machen soll wie es alle machen.
nein, ich meinte damit nur: wenn der kernel mit Funktionen auf GPIOs zugreift, die über ein C-Programm programmiert wurden, dann spricht sicher nichts dagegen, dafür ebenfalls eingebundene C-Funktionen als Subset von C++ mit wrappern zu verwenden.
Ich habe auch nicht gemeint, dass dafür auch schon Lösungen im Raspiforum präsentiert wurden, sondern dass du möglicherweise sehr gute neue Vorschläge bekommen wirst, falls du dein Problem dort neu postest, denn dort sind ja sehr viele extrem versierte C(++) Programmierer unterwegs, die auch die speziellen Raspi-GPIO-Funktionen sehr gut kennen.
Auch wenn ich sonst nicht so häufig HaWe zustimme ;) muss ich ihm doch diesmal Recht geben, wenn vllt auch aus anderen Gründen.
Nun fangen wir zum Einen damit an wie man unter Linux mit dem Kernel interagieren kann: Zum Einen kann man einen Syscall machen. Das sind bestimmte Funktionen die Daten in den Kernel, bzw. daraus bewegen und auf Kernelebene irgendetwas damit machen. Zum anderen kann man auch das Dateisystem unter /proc lesen und schreiben -> Das ruft im Hintergrund aber auch nur irgendwo wieder ein paar tolle Funktionen auf.
Zum Anderen du nennst es Zwiebelsoftware, andere Leute nennen das einen guten Stil der Softwareentwicklung wenn man ein bestehendes Interface kapselt um es seinen Ansprüchen anzupassen. Weil man verhindert damit den tpyischen "Reinvent the wheel" Effekt (http://dl.acm.org/citation.cfm?id=554798 - Gibt es sogar Veröffentlichungen dazu ;) und spart sich eine Menge arbeit. Gibt sogar mindestens ein Softwarepattern dass sich damit beschäftigt (z.B: der Adapter oder der Wrapper). Falls dich das immer noch nicht überzeugt, seeehr viel Software die man irgendwo antrifft am PC basiert darauf dass man zum einen ein einfach C Interface entwickelt hat und dann in der Sprache seiner Wahl ein Frontend drauf gesetzt hat (Was glaubst du wie die ganzen managed Sprachen C# / Java usw. implementiert sind).
Und ein letzter Grund noch warum es durchaus Sinn mach das C interface zu wrappen. Du hast ja inzwischen vllt festgestellt, dass es zwei verschiedene Methoden gibt die GPIOs anzusteuern. Wenn du deinen Wrapper sauber baust, kannst du mit einer Zeile Code auswählen ob du die eine (wiringPi) oder die andere (pigpio) verwenden willst, ohne dass deine SOftware ein anderes Interface verwenden müsste.
Mein Einschätzung dazu ist, dass es wesentlich unsauberer ist Dateisystem zugriffe zu wrappen als bestehenden C Code.
ich meinte das mit den C++ wrappern um C Funktionen herum auch so wie shedepe es schrieb, wenngleich er es auch deutlich präziser formuliert hat.
Ich vergaß allerdings oben zu erwähnen, dass ich wiringPi gerade deswegen auch gern verwende, weil es einerseits einen fd beim öffnen zurückgibt (anstatt einen FILE* handle) und außerdem intern immer berücksichtigt, um welche Art von files es sich handelt, auf die man zugreift - inkl. Sonder-Routinen z.B. für serielle Kommunikation, u.a. wenn es um Besonderheiten wie Puffer etc. geht: ich kann mich dunkel erinnern, dass diese Tatsache auch im Raspberrypi.org C++ Forum das ein oder andere Mal diskutiert wurde.
(Nur zur Vervollständigung, auch wenn es nicht direkt zur Lösung des TOP-Problems führt)
alexander_ro
16.01.2018, 12:48
Das Problem an dem Raspiforum ist auch noch das die immer in so einer unverständlichen Sprache schreiben ... ;)
Englisch ist nicht so meine Sache ... wie ich immer sage: Fremdsprachen sind mir genau das ... Fremd ... ;)
Euer erster Vorschlag war ja: (Mein C++) + (Wiring Pi oder was auch immer) + (Kernel/C API) = Zwiebel
Euer jetziger Vorschlag: (Mein C++) + (Kernel/C API) = (gute Software :) )
Standard C++ Objekte in eigenen Objekten zu benutzen ist jetzt sicher keine Unsaubere Programmierung. Datei System Zugriffe aus Standard C++ Objekten sind Plattformunabhängig und damit in jedem Fall WiringPi oder was auch immer vorzuziehen. Standard C Funktionen oder C++ Objekte sind aus diesem Grund immer wenn es geht zu bevorzugen.
Nichts destotrotz war ich ja der Meinung das das fstream das kann ich es nur nicht gefunden habe. Das klären zu wollen ob es ein Standard Objekt nicht kann was ich brauche halte ich durchaus für Sinnvoll. Damit tue ich ja was jeder sagt ich Versuche das Rad nicht neu zu erfinden und Standard Objekte zu benutzen.
Die Muster Mania ist nicht so mein Ding nur weil jeder Sklavisch nach Mustern schreit und ohne Sinn und Verstand oft auch da verwendet wo die nicht dafür taugen ist es noch lange keine gute Software. Wrapper gab es schon sehr lange vor den Chaoten mit dem Muster Tick. Die schreiben sich zwar deren Erfindung auf die Fahnen aber die Konzepte waren alle schon vorher erfunden. Soweit ich weiß haben das ja die Ami erfunden für die ist es auch nichts neues das die alles Klauen und einen neuen Namen drauf kleben und es als ihr Geistiges Eigentum verkaufen. Trotzdem alles nur geklaut ...
ich persönlich meinte:
du verwendest nur wiringPi für GPIOs und fileIO, wenn es dir nicht auf Performance ankommt, und ggf. pigpio zusätzlich, falls es dir um eine höhere Performance geht. Beide Libs nutzen native C Funktionen bereits in ihrem Rahmen optimal, und man muss IMO gar keine weiteren nativen und/oder Kernel Funktionen selber heranziehen. Die wiringPi/pigpio Funktionen können dann über OOP Methoden in die Klassen/Objekte eingebunden werden. Ob das so richtig formuliert ist und ob shedepe das ggf auch so oder anders meinte, weiß ich nicht.
alexander_ro
16.01.2018, 18:40
Das hatte ich schon so verstanden und das ist auch richtig so. Nur warum sollte ich nicht gleich die C-Funktionen benutzen in meinen eigenen C++ Objekten?
Von der Performance reicht mir im Moment der Zugriff über das Filesystem.
Die C Funktionen sind ja Standard libc. Wenn ich die benutze laufen meine eigenen C++ Objekte auf allen Platinchen die ein Linux/UNIX als OS verwenden (z.B. Gnublin). Ich habe es jetzt nicht überprüft aber ich vermute mal das WiringPi nicht auf jedem Linux Platinchen läuft sondern auf die besondere Hardware des Raspberry zugeschnitten ist. Wäre doch für meine C++ Objekte das bessere Konzept wenn die auch auf != Raspberry auch laufen würden?
Das was ich Probiert habe mit dem fstream geht nur so weit wie ich es schon habe zum Port aus und ein schalten. Das mit den Triggern scheint so nicht mehr machbar zu sein was ich schade finde aber gut kann man nicht ändern.
ja, wenn du es nicht nur für den Pi willst, hast du vermutlich Recht.
Zu meinen Studiumszeiten haben wir das mit
int fileno(FILE *stream);//#include <stdio.h>
gemacht.
Dann hast du deinen Filedescriptor.
Und das geht bei dir nicht? Oder habe ich dein Problem falsch verstanden?
Bin aber in C++ nicht so bewandert. Hat denn fstream::rdbuf()->fd() auch nicht funktioniert?
Sorry, hab jetzt mal deinen Link angesehen. Das fd Problem ist ja eigentlich gar nicht dein eigentliches Problem. Das hast du ja anscheinend gelöst. Du möchtest gern, dass fstream von sich aus ein Event bereit stellt. Wenn das nicht so ist, dann hat sich doch eigentlich damit dein Versuch eine bessere Lösung für poll zu finden als gescheitert erwiesen. Du verbiegst dich jetzt um dann doch am Ende mit poll zu arbeiten. Damit sind wir wieder bei Shedepe und HaWe.
alexander_ro
17.01.2018, 11:02
Das was ich Probiert habe mit dem fstream geht nur so weit wie ich es schon habe zum Port aus und ein schalten. Das mit den Triggern scheint so nicht mehr machbar zu sein was ich schade finde aber gut kann man nicht ändern.
Das war mir ja nun auch schon aufgefallen.
Nein das Problem mit dem fd ist nicht gelöst weil das in meinem Sourcecode das ist was ich probiert habe aber nicht funktioniert.
fstream::rdbuf()->fd() das scheint nicht Standard zu sein und deshalb wurde es aus der libc++ wieder ausgebaut. Haben die ja eigentlich recht.
Die Funktion fileno kenne ich aber die braucht die gefüllte Datenstruktur FILE die bekommt man von der C Funktion open aber nicht vom fstream. Das ist das Problem.
Das fileno nicht geht, habe ich inzwischen auch gelesen, weil sich fstream und FILE unterscheiden. Die einzige Gemeinsamkeit ist, dass sie intern im Unixsystem über fds abgewickelt werden. Deswegen sollte es irgendwie möglich sein, an den Filedescriptor zu kommen. Aber wie schon gesagt, verbiegst du dich total um dann doch nur zu pollen. Wenn fstream das Event nicht direkt anbietet nützt das nun mal nichts.
Was steht denn in dem fstream? Eventuell kann man das im Interval vergleichen, wenn es zB nur ein Byte oder Wort ist.
okay für mich kurz zur info, es geht darum dem GPIO ein signal/interrupt zu entlocken wenn ein GPIO sich ändert?
ich weis dass man eine file mittels mmap in den speicehr mappen kann und so zumindest den zugriff stark vereinfachen kann
obendrein wären da noch die linuxwerkzeuge inotify oder wenn der kernel das nicht hat, dnotify, damit kann man ohne die file zu lesen prüfen ob sie geändert worden ist, ob das mit device files auch funtkioniert konnte ich aber auf die schnelle nicht herausfinden, eventuell wäre das ein ansatz?
EDIT: ---------
habe gerade sogar gelesen dass interrupt unterstützung vom kernel verfügbar sei, nur noch nicht wie ich ddran komme (wie üblich alles in python)
alexander_ro möchte unbedingt fstream nehmen. Da liegt die Schwierigkeit.
okay dann bin ich weider raus, PS wiring pi hat sogar unterstützung für kernel GPIO interrupts zur info :)
ganz dumme Frage, vlt völlig abwegig, denn ich bin kein C++ Programmierer - aber kann man einen Pointer erzeugen, der auf fstream zeigt?
edit,
egal welcher ptr Typ, könnte auch ein void* sein, in der Art
void* vptr;
vptr = (void*)&fstream; // ???
wenn das ginge, dann könnte man per typecasting evtl doch sein fd über fileno() bekommen...?
int fd = fileno( (FILE*) vptr);
alexander_ro
17.01.2018, 20:29
@Ceos: Ja stimmt es geht darum einen GPIO zu benutzen wie einen Interrupt. Ja stimmt inotify sollte auch gehen braucht aber so weit ich auf die schnelle gesehen habe auch den Filedeskripte (fd) den ich wenn ich einen fstream benutze aber nicht habe. Ich hatte erst epoll gefunden damit geht das auch nur mit fd. Es stimmt schon das ich einen fstream benutzen wollte aber so wie es aussieht geht das nicht was ich merkwürdig finde aber auch nicht ändern kann. Was ich nicht benutzen wollte ist Raspberry spezifische Software wie WiringPi. Weil das Kernel und Standard C lösen können und dann ist es kompatibler für andere Platinchen mit Linux. Was ich auch nicht möchte ist eine lib benutzen die letztendlich auch nur Kernel und C benutzt und ich dazu wieder einen Wrapper bauen. Die Software wird nicht besser nur weil man Software Schichten stapelt.
@sast: Das stimmt jetzt so nicht ganz. Das war die Ursprüngliche Idee (fstream oder steam allgemein) es scheint aber damit nicht zu gehen dann werde ich das halt umbauen auf Kernel und C Funktionen. War halt ein Versuch wenn man aber nicht mal was probiert was nicht jeder schon macht gibt es auch nie einen Fortschritt.
@HaWe: Zu so etwas ähnlichem hatte schorsch_76 schon einen Link gepostet. Das sieht aber sehr Merkwürdig aus und nicht so wie wenn man das wirklich tun sollte und ja man kann wie in C von allem in C++ auch einen Pointer bekommen. Den mag der Compiler nicht automatisch in alles andere konvertieren. Aber wenn man mit einem explizitem Cast dem Compiler sagt er soll die Klappe halten und tun was der Programmierer sagt. Dann quetscht der jeden Datentyp in einen anderen egal ob es geht oder nicht. Das sieht der Compiler schmerzfrei weil er es ja dann schriftlich (Cast) hat das der Programmierer am verlorenen Kommunikationssatelliten Schuld ist ... ;)
Ich habe mal gesucht bei C++17 und der dort neuen filesystem Objekte konnte da aber auch nichts entdecken das aussah wie etwas das ich bräuchte. Das finde ich auch merkwürdig. Weil ja filesystem extra eine Funktion hat mit der man feststellen kann ob die Datei ein socket ist. Aber gerade bei einem Socket wäre es ja sehr wichtig eine Funktion zu haben die einem Mitteilt wenn neue Daten zum abholen da sind. Aber vielleicht wollten die sich das für den nächsten Standard aufheben damit die später auch noch was neues einbauen können.
du hast Recht, ich fand die Idee auch zuerst - sagen wir: - verwegen.
Dennoch, nach dem Motto "alles ist ein File" und "Pointer sind auch nur Speicher-Adressen" war meine Idee schlicht
fstream ist ein file,
FILE ist ein file,
jeder File hat eine Adresse,
jeder File (zumindest FILE) hat einen File Descriptor,
also warum nicht mit dem Pointer vom einen auf den Wert vom anderen Pointer verweisen, genau wie man mit einem void* auf den Wert eines int* oder auf ein char* oder float* verweisen kann und umgekehrt.
Probiers doch einfach mal aus, mehr als 35 EUR wird es schlimmstenfalls nicht kosten ;)
PS,
notfalls, falls gpp streikt, bliebe immer noch -fpermissive :P
- - - Aktualisiert - - -
PS,
eventuell ließe sich das oben gesagte sogar noch etwas "obfuscated" zusammenziehen:
int fd = fileno( (FILE*)&fstream );
alexander_ro
17.01.2018, 21:23
Ich habe das mal so probiert:
std::cout << fileno ((FILE*) &fileIntPortValue) << std::endl;
Da bekomme ich abwechselnd 0, 1 oder -1. Was eigenltich nicht stimmen kann weil ja stdin, stdout und stderr bereits die Filenummern 0, 1, 2 belegen.
ok, wär' ja auch zu schön gewesen, aber immerhin, auch wenn es Unsinn war, fand ich war es wenigstens einen Versuch wert :)
(wobei ich aber auch zuwenig von C++ verstehe, um zu sagen zu können, ob (FILE*) &fileIntPortValue wirklich dasselbe ist wie (FILE*) &fstream)
edit,
war blöd formuliert, ich meinte ob fileIntPortValue die echte Adresse ist, wo im fstream die file Daten aktuell anfangen.
alexander_ro
17.01.2018, 23:53
Ja probieren kann man das immer.
Von der Theorie her könnte so etwas schon gehen. Der Pointer zeigt ja auf das erste Byte der Variable vom Typ fstream im Speicher. Wenn jetzt die Datenstructur FILE am Anfang des Speicherbereichs den fstream belegt steht könnte man es einfach benutzen wie wenn es ein FILE wäre. Ich weiß aber nicht ob es überhaupt dem Programmierer möglich ist fest zu legen welche Daten einer Klasse im Speicher am Anfang liegen.
// int ist der Datentyp, Nummer der Name der Variable damit der Programmierer die Benutzen kann.
int Nummer;
// fstream ist der Datentyp, fileIntPortValue der Name der Variable.
// C++ Objekte werde einfach wie interne Datentypen benutzt
fstream fileIntPortValue;
Damit man ein C++ Objekt benutzen kann muss man immer eine Instanz davon erzeugen und das macht man genauso wie bei internen Datentypen in dem man eine Variable definiert. Ein Pointer auf den Datentype ist ja nicht möglich das ist auch bei den internen Datentypen wie int nicht möglich.
Weil das Kernel und Standard C lösen können und dann ist es kompatibler für andere Platinchen mit Linux
Was ich darüber so gelesen habe, brauchst du Kernelunterstützung um "echte" Interrupts zu bekommen, daher erwähnte ich das mit Wiring Pi und der Unterstützung am Rasppbery Pi, aber ohne Kernelunterstützung kannst du wohl maximal so schnell werden wie der Kernel dir für das GPIO-device ein udate macht und dann über inotify ein signal geben lassen. Aber ob es auch andere wege gibt habe ich leider keine Ahnung.
Inotify brauch übrigens keine FDs sondern nur den Pfad zur überwachenden Datei/Ordner (achtung bei änderungen an dateien im ordner selbst werden nicht zwingend signale vom ordner-notifier ausgegeben, das ist wohl vom dateisystem abhängig)
alexander_ro
18.01.2018, 09:04
GPIO sind ja keine echten Interrupt. Deshalb bezeichne ich die auch immer als Trigger das kommt besser hin. Ein echter Interrupt muss von der Hardware auch als solcher unterstützt werden und echte Hardware Interrupt macht der Kernel selber die Steuerung. Kann so ein Ereignis aber auch wieder an den Userspace weiterreichen. Ich weiß nicht ob der Raspi an seinem Stecker einen echten Hardware Interrupt herausführt. Bei den AVR gibt es so was aber auch dort kann das nicht jeder Port.
Man kann aber so tun als ob ein GPIO ein Interrupt ist das ist dann ein Software Interrupt so zu sagen. So ähnlich wie das auch bei PWM ist die kann man in Hardware haben und in Software Simulieren.
Inotify kenne ich jetzt nicht so gut ich weiß auch nicht wie schnell das ist weil es relativ kompliziert aussieht. Für diesen Zweck würde ich jetzt eher epoll oder poll benutzen. Wenn man dem glaubt was geschreiben steht ist epoll schneller als poll, Dabei geht es ja eigentlich nur darum das das warten auf ein Ereignis möglichst wenig Rechenzeit verbraucht.
Hier hatte ich das her: http://opensourceforu.com/2011/04/getting-started-with-inotify/
(http://opensourceforu.com/2011/04/getting-started-with-inotify/)Der benutzt fd für den inotify init. Das hatte ich übersehen das es kein File fd ist.
inotify hat aber einen Nachteil gegenüber poll/epoll man muss ja selber in einer Schleife lesen ob eine Nachricht da ist. Dann kann man genauso gut in einer Schleife prüfen ob der Port sich geändert hat. inotify würde ich jetzt mal sagen ist erst dann interessant wenn man mehrere Dateien überwachen muss.
(http://opensourceforu.com/2011/04/getting-started-with-inotify/)
GPIO sind ja keine echten Interrupt. Deshalb bezeichne ich die auch immer als Trigger das kommt besser hin. Ein echter Interrupt muss von der Hardware auch als solcher unterstützt werden und echte Hardware Interrupt macht der Kernel selber die Steuerung. Kann so ein Ereignis aber auch wieder an den Userspace weiterreichen. Ich weiß nicht ob der Raspi an seinem Stecker einen echten Hardware Interrupt herausführt. Bei den AVR (http://www.rn-wissen.de/index.php/AVR-Einstieg_leicht_gemacht) gibt es so was aber auch dort kann das nicht jeder Port.
genau daher mein nachsatz, wiringPi kann genau das auf raspberrys :)
aber was das inotify angeht, versuchs makl mit folgender webseite (englisch, ich weis) https://www.ibm.com/developerworks/linux/library/l-ubuntu-inotify/index.html
in der erklärung sieht das relativ simple aus, du macht das init, dann ein add_watch auf die datei (also den pfad) und auf die eventqueue (die du vom add_watch bekommst) ein read, das so lange blockt bis die datei sich tatsächlich ändert und das event gesendet wird. Aus der queue siehst du dann welches event, führst dein read auf der datei aus, holst das ergebnis und löst ggf. ein signal oder einen callback aus. Optimal läuft das natürlich nur als multithread aber ich habe auch gelesen dass inotify angeblich selber in der lage sein sollte signals auszulösen, wenn cih finde, reich ich's nach
wenn ich den OP recht verstanden habe, will er ja kein wiringPi, und wiringPi Sourcecode ist zwar kein Hexenwerk und ist auch bereits auf jedem neueren Raspbian via apt fertig installiert und einsehbar, aber wegen des Raspi device trees ist es dennoch nicht unbedingt zu anderen Linux kompatibel, noch nicht mal unbedingt zu anderen Debians (z.B. nicht zu ev3dev, auch eine Debian distri.).
alexander_ro
18.01.2018, 11:54
WriingPi mach aus einem GPIO aber auch keinen echten Hardware Interrupt.
Wenn es nicht zwingend sein muss würde ich die Lösung gerne Hardware unabhängig halten. Da sind halt Kernel und C Funktionen meiner Meinung die besser Wahl.
Ich schau mir das mal an was IBM von inotify schreibt. Die Seite die ich gefunden hatte war ja auch Englisch findet man leider ja öfter nicht anderes. Ich probier das auch mal aus mit inotify dann kann ich auch mal gucken wie schnell das ist. Stimmt schon an die blockierenden read habe ich nicht mehr gedacht.
WriingPi mach aus einem GPIO aber auch keinen echten Hardware Interrupt.
vermutlich, nach meinem begrenzten Verständnis, hast du damit Recht.
Hier äußert sich der Meister des wiringPis persönlich dazu:
https://www.raspberrypi.org/forums/viewtopic.php?p=146408#p146408
s.a. hier unter "Interrupts"
https://projects.drogon.net/raspberry-pi/wiringpi/functions/
WriingPi mach aus einem GPIO aber auch keinen echten Hardware Interrupt.
neuerem kernel sei dank schon, wie gesagt der einzige grund wrum ich es nochmal erwähnt hatte ... leider aber eben limitiert auf raspbery pi
https://www.raspberrypi.org/forums/viewtopic.php?t=74643
viel erfolg beim probieren mit inotify, und denk dran, wenn der kernel älter ist, musst du auf dnotify zurückfallen aber dann wirds unperformant ... zumindest nach dem was ich bei vergleichsdiskussionen so gelesen habe :)
PS: -----------
du kansnt auch die realtime patches installieren wenns richtig dramatisch werden sollte mit den timings, aber dann hast du natürlich nichts universelles mehr
alexander_ro
18.01.2018, 17:18
@Ceos: So alte Kernel gibt es doch für den Raspberry gar nicht mehr. Bei IBM ist für inotify von Kernel 2.6 die rede. Ich habe zwar ein Gentoo auf meinem laufen ich benutze aber den Kernel den auch das Raspian benutzt. Die boot Partition habe ich einfach kopiert.
Das ist ein Irrtum zu glauben das etwas schneller wird mit den Realtime Funktionen des Kernels. Realtime garantiert nur eine Reaktion in einer bestimmten Zeit. Diese Zeit muss aber auch im Rahmen der Möglichkeiten des Systems liegen. Deutlich schneller würde es nur wenn man die Filesystem Zugriffe durch Memory Mapped IO ersetzt. Das will ich aber nicht weil das wieder andere Probleme mit sich bringt. Trotzdem will ich aber auch nicht sinnlos Rechenzeit verschwenden.
Ob das echte Hardware Interrupts sind müsste man im Datenblatt des Prozessors nachlesen. Das ist mir aber im Moment zu viel Aufwand.
Realtime garantiert nur eine Reaktion in einer bestimmten Zeit
darauf kams doch an oder nicht?
Ob das echte Hardware Interrupts sind müsste man im Datenblatt des Prozessors nachlesen
ja sind es beim raspberry pi + wiring pi seitdem der kernel ISR unterstützung bekommen hat
Deutlich schneller würde es nur wenn man die Filesystem Zugriffe durch Memory Mapped IO ersetzt. Das will ich aber nicht weil das wieder andere Probleme mit sich bringt.
seh ich genau so ... in beiderlei hinsicht :)
alexander_ro
19.01.2018, 05:36
darauf kams doch an oder nicht?
Stimmt ist nicht unwichtig. Aber wenn der Raspberry nicht bis zum letzten Prozent Rechenleistung ausgelastet ist sind die Abweichungen in der Reaktionszeit auch ohne Realtime sehr gering. Selbst wenn Gentoo Updates compiliert das relativ hohe Last verursacht reicht scheinbar die verbleibende Rechenzeit um einige Ports ohne nennenswerten Zeit Verlust zu überwachen und zu schalten. Das macht der Kernel schon recht ordentlich und ist so für meine Zwecke mehr als ausreichend.
okay freut mich und danke für den informativen test :)
alexander_ro
20.01.2018, 10:13
Bin ja noch gar nicht fertig mit dem Testen ...
Danke für eure Hilfe.
alexander_ro
21.01.2018, 18:31
Jetzt läuft es mit inotify. Es macht auch einen Unterschied ob man rising, falling oder both benutzt. Nur Merkwürdig ist das falling und rising invertiert erscheinen. Kann das an den internen Pullup oder Pulldown Widerständen liegen? Ein aktiver Pullup würde doch wie ein Inverter wirken. Nur weiß ich nicht wie man die konfigurieren kann ...
Ich habe jetzt gelesen das die internen Pull Up/Down nach dem booten ausgeschaltet sind. Dann lag es daran das der Port bei mir dann offen war. So kleine Mosfet wie in den Prozessoren wird das bisschen Energie das an einer offenen Leitung einstrahlt schon reichen das er einschaltet. Mit einem externen Pull Down Widerstand funktioniert es dann einwandfrei. Wenn man immer einen gesicherten Zustand haben will wird man so externe Widerstände nehmen müssen. Weil der interne beim booten oder Reset ja nicht vorhanden ist und erst beim Start der Steuerungssoftware konfiguriert wird.
Nach einigen Tests mit der inotify Lösung sieht man schon das das nicht die schnellste ist. Wenn man in einer Endlos Schleife einen Port ein/ausschaltet und den anderen als Eingang für der Trigger benutzt. Verliert er sehr viele Impulse die der Trigger nicht mitbekommt. Bisher habe ich als kleinsten Wert mit einer Verzögerung von einer Millisekunde getestet. Damit funktioniert es problemlos. Ob noch kleinere Werte möglich sind habe ich bisher nicht getestet. Für die Lösung von Mechanischen Steuerungsaufgaben sollte es aber ausreichend sein.
for (;;)
{
std::cout << "Port 2: 1" << std::endl;
ioPort2 << 1;
milliSleep (1); // benutzt intern nanosleep
std::cout << "Port 2: 0" << std::endl;
ioPort2 << 0;
}
Vermutlich wäre die Lösung mit epoll schneller und auch recht gut Hardware unabhängig. Bei epoll spart man sich ja einmal die Zugriffe über das Filesystem die schon sehr viel Zeit kosten. Alles Memory Mapped ist zwar schnell aber leider dann auch 100% Hardware abhängig.
Falls es jemanden interessiert habe ich den aktuellen Stand in mein git Repo kopiert. Das ist noch nicht fertig aber man kann sehen wie es geht. Fehlerhandling usw. muss man noch anständig machen. https://git.hts-software.de/index.html/Athena-Api/tree/Gpio/Gpio.hpp
NumberFive
31.10.2018, 09:54
Alexander bist du jetzt mit deinem Code zufrieden ?
Ich möchte einen Drehgeber damit abfragen die Zeiten die du gemessen hast sehen irgend wie passen aus.
alexander_ro
31.10.2018, 10:17
Ja der Code funktioniert auf einem Raspi mit Gentoo Linux sollte aber mit allen anderen halbwegs aktuellen Distributionen auch funktionieren. Wenn Du was findest das nicht geht wäre es nett wenn Du hier schreibst was es ist damit ich es reparieren kann. Du musst bei Deiner Anwendung halt aufpassen das der Drehgeber die Impulse nicht schneller generiert als die vom Controller verarbeitet werden können.
Hier der neue Link weil ich für die git Web Zugriffe ein anderes Programm benutze geht der oben nicht mehr. Die Domain ist aber die gleiche geblieben.
https://git.hts-software.de/cgit.cgi/Athena-Api/tree/Gpio/Gpio.hpp
NumberFive
31.10.2018, 10:33
Ich habe ein Aktuelles Debian drauf da sollte der Kernel passen denke ich. Ja werde schreiben wenn ich was finde.
Das der Link jetzt anders ist habe ich schon gemerkt habe aber den Code schon gefunden gehabt danke für den neuen Link.
Bei dem wort Drehgeber habe ich wohl mich falsch Ausgedrückt bzw es ist halt so ein Poti was schalte da dreht ein Mensch dran nicht ein Motor deshalb hoffe ich das es klappt.
Lautstärke einstellen ist die Funktion.
alexander_ro
31.10.2018, 10:56
Ist ja auch ein Drehgeber wenn den Menschen bedienen gibt das sicher keine Probleme.
NumberFive
09.11.2018, 06:40
hast du das Thema PWM schon mal betrachtet ? Wenn ich jetzt mit deinem Code auf externe Libs verzichte brauche ich noch eine Lösung für I²C und PWM. Das PWM brauche ich für den Lüfter.
http://www.raspberry-projects.com/pi/programming-in-c/i2c/using-the-i2c-interface damit sollte das mit dem MCP23017 klappen der ist ja vom Protokoll her nicht wirklich schwer.
Aber bei PWM habe ich noch so gar keine Idee
alexander_ro
09.11.2018, 11:21
I2C habe ich bisher noch nichts gemacht. Unter Linux ist das ja auch nur ein Devicefile das man mit open öffnet und dann die Daten schreibt. Für den SPI bei einem Gnublin habe ich das mal gemacht.
// Copyright 2013 HTS-Software Unternehmensberatung
// Alexander Schucha
//
// This file is part of Athena-Api.
//
// Athena-Api is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Athena-Api is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with Athena-Api. If not, see <http://www.gnu.org/licenses/>.
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <atomic>
#include <chrono>
#include <thread>
#include <time.h>
#include <iostream>
#include <fstream>
#include <sys/ioctl.h>
#include <linux/types.h>
#include <linux/spi/spidev.h>
class Spi
{
public:
Spi (const std::string& strChipSelect,
const std::string& strDevFile,
const unsigned int uiBandbreite = 100000,
const unsigned char ucBitAnzahl = 8,
int iDebug = 0) : strIntChipSelect (strChipSelect),
strIntDevFile (strDevFile),
iIntDebug (iDebug)
{
// Debug Messages
if (iIntDebug == 1)
{
std::cout << "Start Spi Konstruktor ... " << std::endl;
std::cout << "strIntChipSelect: " << strIntChipSelect << std::endl;
std::cout << "strIntDevFile: " << strIntDevFile << std::endl;
}
iIntDevFile = open(strDevFile.c_str(), O_RDWR);
if (iIntDevFile < 0)
std::cout << "SPI Device File konnte nicht geöffnent werden (SPI-Kernel Modul geladen? root?)." << std::endl;
// SPI Bandbreite einstellen
if (ioctl (iIntDevFile, SPI_IOC_WR_MAX_SPEED_HZ, &uiBandbreite))
std::cout << "SPI Bandbreite konnte nicht eingestellt werden" << std::endl;
// SPI Anzahl Bits einstellen
if (ioctl (iIntDevFile, SPI_IOC_WR_BITS_PER_WORD, &ucBitAnzahl))
std::cout << "SPI Anzahl Bits konnte nicht eingestellt werden" << std::endl;
}
int operator<< (std::string strDaten)
{
if (iIntDebug == 1)
std::cout << "Daten länge: " << strDaten.size () << std::endl;
int status;
struct spi_ioc_transfer xfer;
xfer.tx_buf = (unsigned long) strDaten.c_str ();
xfer.len = strDaten.size ();
xfer.rx_buf = 0;
xfer.delay_usecs = 0;
xfer.speed_hz = 0;
xfer.bits_per_word = 0;
status = ioctl(iIntDevFile, SPI_IOC_MESSAGE(1), &xfer);
if ((status < 0) && (iIntDebug == 1))
std::cout << "SPI Daten senden fehlgeschlagen." << std::endl;
}
int operator<< (__u8* cDaten)
{
if (iIntDebug == 1)
std::cout << "Daten länge: " << sizeof (__u8) << std::endl;
int status;
struct spi_ioc_transfer xfer;
xfer.tx_buf = (unsigned long) cDaten;
xfer.len = sizeof (__u8);
xfer.rx_buf = 0;
xfer.delay_usecs = 0;
xfer.speed_hz = 0;
xfer.bits_per_word = 0;
status = ioctl(iIntDevFile, SPI_IOC_MESSAGE(1), &xfer);
if ((status < 0) && (iIntDebug == 1))
std::cout << "SPI Daten senden fehlgeschlagen." << std::endl;
}
~Spi (void)
{
if (iIntDebug == 1)
std::cout << "Start Spi Destructor ... " << std::endl;
close(iIntDevFile);
}
private:
std::string strIntChipSelect;
std::string strIntDevFile;
int iIntDevFile;
int iIntDebug;
};
Das sollte relativ leicht zum umbauen sein ist ja beides eine serielle Verbindung. Geräte Datei öffnen und Daten senden/empfangen müsste fast gleich sein nur die Daten für die Abwicklung des Protokolls sind unterschiedlich. Ich kann so was schon schreiben weiß aber noch nicht was ich zum Testen benutzen könnte. Vielleicht habe ich noch ein Arduino Teil herumliegen.
PWM habe ich auch noch nicht gemacht würde es aber auch schon brauchen. Kommt halt darauf an ob Du das in Software oder Hardware machen willst. Unter Linux kann man Software PWM recht Rechenzeit sparsam bauen weil der Kernel in der Wartezeit was anderes tun kann. Hardware PWM geht auch wieder über die Devicefiles.
so etwa:
https://jumpnowtek.com/rpi/Using-the-Raspberry-Pi-Hardware-PWM-timers.html
NumberFive
09.11.2018, 19:51
Nach dem Code den ich gefunden habe ist I²C noch einfacher siehe Link im Pos davor.
PWM ob Hardware oder Software ist mir im Moment egal da ich nur einmal brauche für den Lüfter und ich bin der Meinung der PI hat nur ein Hardware PWM.
Hast du eine Link zu der Beschreibung der DeviceFiles ich finde da immer nix ?
Ich habe mal mein test PRG für die Pins angehängt. Ein bisschen was habe ich umgebaut. Die Exception sind in der "richtigen" Software dann drin. Bei Test PRG habe ich es mal Weg gelassen.
Ich hoffe das so Ok für dich. Auch habe ich Programm in dem ich es Nutzen möchte einen Logger das hier auskommentiert.
Wenn man im Netz sucht kommt halt immer bei einer der beiden Libs raus. Libs machen halt immer das Crosscompile so aufwendig.
Nach dem Code den ich gefunden habe ist I²C noch einfacher siehe Link im Pos davor.
PWM ob Hardware oder Software ist mir im Moment egal da ich nur einmal brauche für den Lüfter und ich bin der Meinung der PI hat nur ein Hardware PWM.
Hast du eine Link zu der Beschreibung der DeviceFiles ich finde da immer nix ?
Ich habe mal mein test PRG für die Pins angehängt. Ein bisschen was habe ich umgebaut. Die Exception sind in der "richtigen" Software dann drin. Bei Test PRG habe ich es mal Weg gelassen.
Ich hoffe das so Ok für dich. Auch habe ich Programm in dem ich es Nutzen möchte einen Logger das hier auskommentiert.
Wenn man im Netz sucht kommt halt immer bei einer der beiden Libs raus. Libs machen halt immer das Crosscompile so aufwendig.
Soweit ich weiß, hat der Pi mit 40 Pins 2 Hardware pwm (BCM 12+13) und prinzipiell beliebige Software pwm. Hardware pwm braucht root Rechte.
alexander_ro
10.11.2018, 15:58
Für den I2C habe ich schon mal eine Klasse angefangen zu bauen bin aber noch nicht ganz fertig.
Für PWM war der Link oben als Info gedacht. Dort stehen im unteren Teil die Devicefile Namen.
Der schreibt hier zum Beispiel den Wert "10000000" in die Datei "/sys/class/pwm/pwmchip0/pwm0/period". Die Datei einfach mit open öffnen und dann mit wirte den Wert in die Datei schreiben. Bei mir ist allerdings das Verzeichnis "/sys/class/pwm/" leer. Vermutlich muss man PWM erst irgendwie aktivieren beim booten. Der Raspi lädt ja nicht automatisch alle Treiber. Den Kerneltreiber wird man auch noch laden müssen.
Man findet erstaunlich wenig zu Hardware PWM und Raspi. Einige schreiben das der einzige PWM Anschluß für den Audio Port benutzt wird.
Software PWM ist ja einfach: ein Thread in dem Du den Port aus und ein schaltest und nach jedem Schalten ein CPU freundliche Wartezeit einbaust. (z.B. mit std::this_thread::sleep_for(std::chrono::milliseco nds(100));). Damit kannst Du dann die Zeit für Port ein oder aus einstellen. Wenn Du das in einer Lamda Funktion machst kannst Du über zwei externe Variablen die Zeiten beliebig einstellen. Das wollte ich als eine Spezialisierung meiner Gpio Klasse bauen.
Ich wusste doch ich habe das schon mal gemacht. Für einen Temperatursensor auch für den Gnublin ist aber alles der Sympathische Pinguin ... :)
// Copyright 2014 HTS-Software Unternehmensberatung
// Alexander Schucha
//
// This file is part of Athena-Api.
//
// Athena-Api is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Athena-Api is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with Athena-Api. If not, see <http://www.gnu.org/licenses/>.
//************************************************** ****************************
//* Neuentwicklung 15.08.2014 *
//************************************************** ****************************
// Device File anlegen:
// mknod /dev/i2c-1 c 89 1
//
// Das Programm benötigt root Rechte !!!
// Wegen den Zugriffen auf die Hardware-Ports
#include <cstring>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <atomic>
#include <chrono>
#include <thread>
#include <time.h>
#include <iostream>
#include <fstream>
#include <sys/ioctl.h>
#include <linux/types.h>
#include <linux/i2c.h>
#include <linux/i2c-dev.h>
class I2c
{
public:
I2c (const std::string& strDevFile,
const unsigned char ucI2cAdr,
int iDebug = 0) : strIntDevFile (strDevFile),
ucIntI2cAdr (ucI2cAdr),
iIntDebug (iDebug)
{
// Debug Messages
if (iIntDebug == 1)
{
std::cout << "Start I2c Konstruktor ... " << std::endl;
std::cout << "strIntDevFile: " << strIntDevFile << std::endl;
}
iIntDevFile = open(strDevFile.c_str(), O_RDWR);
if (iIntDevFile < 0)
{
std::cout << "I2C Device File konnte nicht geöffnent werden." << std::endl;
exit (0);
}
if (ioctl(iIntDevFile, I2C_SLAVE, ucI2cAdr) < 0)
{
std::cout << "I2C Adresse als Slave: " << ucI2cAdr << std::endl;
exit (0);
}
}
friend short I2c::operator>> (short iReturn, short iValue)
{
return getTemp ();
}
short getTemp (void)
{
// Lese einen Wert über den I2C Bus.
unsigned char ucBuffer[2];
int iLaenge = 2;
memset (ucBuffer, 0, sizeof (ucBuffer));
if (read(iIntDevFile, ucBuffer, iLaenge) != iLaenge)
std::cout << "I2C lesen fehlgeschlagen, Länge: " << iLaenge << std::endl;
// MSB speichern
short sWert = ucBuffer[0];
// MSB an die richtige position schieben.
sWert <<= 8;
// LSB an das MSB anfügen
sWert |= ucBuffer[1];
// Bit 0-4 werden nicht benutzt beim LM75
sWert >>= 5;
// Konvertiere die Daten in den Temperatur Wert.
if(ucBuffer[0] & 0x80)
{
// Temperatur negativ
sWert = sWert | 0xF800;
sWert =~ sWert + 1;
sWert = sWert * (-0.125);
return sWert;
}
else
{
// Temperatur positiv
sWert = sWert * 0.125;
return sWert;
}
}
~I2c (void)
{
if (iIntDebug == 1)
std::cout << "Start I2C Destructor ... " << std::endl;
close(iIntDevFile);
}
private:
unsigned char ucIntI2cAdr;
std::string strIntDevFile;
int iIntDevFile;
int iIntDebug;
};
NumberFive
12.11.2018, 05:31
Dank die Infos muss ich jetzt mal verarbeiten.
Selbst wenn der PWM für den Sound verwendet würde sollte das bei mir egal sein den ich hole den Sound per HDMI aus dem PI. Und das man dafür den PWM braucht kann ich mir gerade nicht so ganz vorstellen.
Leider war ich das ganze WE unterwegs und konnte das jetzt erst lesen. Leider muss ich mich erstmal um das Stromversorgungs Problem Kümmern den das gefährdet gerade das ganz Projekt.
Der Amtel der Stromversorgung Bootet nicht wenn die RX Leitung angeschlossen ist. Aber ich will den Thread nicht Kapern. Ich melde mich so bald ich an dem Thema I²C und PWM wieder drin bin.
Eines noch die ganzen Sachen kommen in einen Systemd Backend Dienst so das rechte hier nicht so problematisch sind. Die GUI reden mit dem Backend per TCP.
Aber das sollte alles auf meiner HP zu lesen sein Link in der Fußzeile.
alexander_ro
12.11.2018, 14:06
HDMI Sound ist ja nur Digital. Du musst auf der anderen Seite halt einen Digital/Analog Wandler haben der aus den Daten ein Analoges Signal macht. Ich habe für Sound eine USB Soundblaster Soundkarte. Will man den PWM vom Raspi Klinken Sound benutzen wird man den Treiber entfernen müssen und vermutlich für eine normale PWM Anwendung einen anderen Treiber benötigen. Weiß ich noch nicht wie das geht. Ich baue mal das I2C Ding das dauert so sicher ein paar Tage weil ich ja auch ein Programm für den Arduino brauche damit ich zum Testen zwischen Raspi und Arduino Daten verschieben kann.
Ich weiß da nichts genaues darüber aber die Controller können zum Teil über serielle Schnittstelle booten. Also er lädt sein Programm über die serielle Schnittstelle und beginnt erst dann mit der Ausführung. Dann kann es sein das Du den Port auf eine bestimmte Art beschalten musst damit er erkennen kann das Du nicht über seriell booten willst. Evtl. auch so ein Fuses Ding das man da das booten über seriell ausschalten muss. Oder ein bootloader macht das könnte auch sein.
NumberFive
12.11.2018, 19:19
Ich habe einen HDMI Splitter mit Analog Ausgang das war für mich die Beste Lösung wenn es auch nicht gerade Billig war. Ich halte von den USB Soundkarten nicht viel. Per Splitter habe ich laut Datenblatt auch 5:1 aber in Realität habe ich es noch nicht zum Laufen bekommen (5:1) 2:1 geht. Der Splitter mach 48Khz bei 24Bit und das hört man dann schon. Natürlich nicht bei einer einfachen MP3 Datei.
Der Amtel steckt auf einer eigenen Platine ist kein Arduino und wenn ich einen 10KOhm Wiederstand in die RX Leitung geht alles wie gewünscht muss also noch suchen wo der Strom falsch abbiegt.
Denk dran der Arduino hat 5V am i²c und der PI 3,3 V aber das hast du sicher auf dem Schirm. Ich brauch das I²C für den MCP23017 damit ich Relais später schalten kann.
Wenn ich was habe werde ich es hier Posten.
NumberFive
13.11.2018, 05:37
Ich habe jetzt mal bei wiringPi und bei pigpio gelesen und wenn ich mir da das Thema Hardware PWM so durch lese gibt es wohl dann mit der ein oder anderen Zusatzhardware Probleme. Da ich aber nicht möchte das mein Prg zu viele Einschränkungen macht. Werde ich wohl eher auf Software PWM setzen müssen. Ich brauche das ja auch "nur" für den Lüfter da ist ein sauberes PWM nicht so wichtig Hauptsache ist das der Lüfter nicht immer voll dreht weil dann ist laut. Mal sehen ob ich das Ressourcen schonend hin bekomme.
Ich habe jetzt mal bei wiringPi und bei pigpio gelesen und wenn ich mir da das Thema Hardware PWM so durch lese gibt es wohl dann mit der ein oder anderen Zusatzhardware Probleme. Da ich aber nicht möchte das mein Prg zu viele Einschränkungen macht. Werde ich wohl eher auf Software PWM setzen müssen. Ich brauche das ja auch "nur" für den Lüfter da ist ein sauberes PWM nicht so wichtig Hauptsache ist das der Lüfter nicht immer voll dreht weil dann ist laut. Mal sehen ob ich das Ressourcen schonend hin bekomme.
Stimmt, wiringPi und pigpio sind ja nur Wrapper um die "eingebauten" BCM-Funktionen für Hardware PWM, machen also beide nichts "neues". Für Software-pwm nutzt wiringPi nur POSIX pthread, kein C++ std::thread (wiringPi nutzt niemals C++ Funktionen, ausschließlich ANSI C).
Auch für I2C nutzt wiringPi nur Wrapper um BCM-Funktionen.
NumberFive
14.11.2018, 12:50
wiringPi sagt ja ganz klar das es C ist und sein will ergo ist es richtig so das es kein std::thread benutzt.
Wobei zu mindestens bei Debian mit g++ zur zeit std::thread das selbe ist wie pthread. Klar wenn sich das ändert muss man den Code nicht anpassen.
Beide Libs mach schon ein bisschen mehr als nur die BCM Funktionen zu Wrappen zum Beispiel das die PIN's immer die selbe Nummer habe. was bei der Implementierung hier nicht so ist Ergo muss man immer genau wissen was für ein PI das gerade ist.
NumberFive
16.11.2018, 06:40
so auf die schnell mal zwei klassen zusammen gehämmert auch mehr C als C++. Aber mein mcp23017 reagiert und schaltet die LED an und aus.
alexander_ro
18.11.2018, 11:06
Oh das neue Forum ist schon zäh in der Benutzung. Angehängte Dateien darf ich nun scheinbar nicht mehr lesen ... :( und die Benachrichtigung über neue Beiträge ging auch nicht mehr.
<edit>Das alte Forum gibt es ja noch da darf ich auch die Datei herunterladen ... :)</edit>
Ich habe jetzt mal meine alte Klasse aufgeteilt. In die I2C Kommunikation und die Implementierung für die spezielle I2C Hardware wie Sensoren, Porterweiterungen, Wandler, usw.
https://git.hts-software.de/cgit.cgi/Athena-Api/tree/I2c
Sehr weit bin ich noch nicht gekommen ich hatte mit dem Gentoo Update auf dem Raspberry das Problem das er immer während dem Update abstürzte. Das lag an einer nicht ganz Stabilen Stromversorgung. Irgendwie das Netzteil kaputt gegangen.
Was ich nicht wirklich verstehe ist warum man neue Projekte wie wiringPi mit total veralteter Software Architektur überhaupt anfängt. Die Software Branche Programmiert noch wie vor 30 Jahren und Wundert sich das nichts vorangeht. Wegen den Ports noch also meine Pis haben unter Linux immer die gleichen Nummern. Nur zwischen verschiedenen Platinen weicht das ab. Also z.B. Gnublin und Raspi was aber normal ist un kaum zu verhindern.
NumberFive
19.11.2018, 07:14
also ich glaube jetzt verwechselt du was ja ich kann deine Kritik absolut folgen das was den C11 und C14 Standard bringt wir durch den C# hyp voll kommen übersehen. Auch das Thema Energie Effizienzen ich meine damit um das selbe zu Tun muss ich immer mehr Energie rein stecken weil Programmierer sich nicht die Finger schmutzig machen wohlen. Der GC der absolute Performens Killer.
Aber so was wie wiringPi in C zu schreiben macht schon sind gerade vor dem Hintergrund das bei Embedded systemen nicht immer der C++ Support geben ist C immer da ich ja einen Kernel bauen muss. Ok die ganz harten schreiben den auch in Assembler aber da bin ich dann raus.
https://www.codeproject.com/Articles/1173585/Adventures-with-the-Pi-part
Das letztere zum PI glaube ich nicht so ganz den der PI hat mehr als ein Layout und da Ändern sich sehr wohl die Pin nummern je nach Revision der Platine.
https://github.com/DerKleinePunk/TryGPIOWithPI
Weil mir der Speicher zum Hochladen ausgeht und wenn es Problem bei Download gibt ist so vielleicht besser. Ich hoffe das für dich Ok sonst lösche ich das wieder kein Ding.
Das Forum scheint wirklich mit den Ur-Accounts Probleme zu haben ich fliege auch relativ häufig raus das nervig daran dann sind die Text weg.
alexander_ro
19.11.2018, 11:04
Die ganzen Aufsteckplatinchen wären nicht austauschbar wenn es nicht die gleichen Pins wären. Es ist doch gerade die Kompatibilität zwischen den Raspi die den so beliebt machen. Man darf nur nicht verwechseln das die Benennung der Devicefiles manche Linux Distributionen anderes machen als andere. Das sollte eine Bibliothek aber auch nicht verstecken. Es ist nicht gut Sachen in einer Lib zu lösen die nicht allgemeingültig gelöst werden können. Ich habe drei verschiedene Layout die sind kompatibel und da unten steht auch meine PIs.
Wenn es keinen C und C++ Compiler zu einer CPU gibt würde ich die erst gar nicht einsetzten. Das wiringPI wurde für den Pi gemacht bei mir kann der ein Gentoo selber Compilieren da gibt es C und C++ in großen Mengen. Gut da dauert einen llvm zu übersetzen schon mal 48 Stunden aber es geht. Ich kann nun nicht erkennen warum man dann eine Bibliothek nicht in C++ schreiben sollte. wiringPi wurde für eine Rechnerklasse geschrieben die nicht wirklich in das Genre Embedded passt. Somit auch nicht die Einschränkungen hat die vielleicht ein Atmega8 hat. Daher macht es keinen Sinn eine Software Architektur neu zu bauen die im letzten Jahrtausend schon als veraltet galt.
Performance ist sicher auch wichtig aber als erstes sollte die Fehlervermeidung und die Sicherheit einer Software stehen und bei beidem hilft eine Modere Software Architektur. Auch ist es schlicht nicht wahr das C++ Software langsamer ist als C. Die Lüge wurde von C Programmieren verbreitet die C++ nie verstanden hatten und damit versuchten zu Programmieren. Klar schlecht geschriebene C++ Software ist langsam aber schlecht geschriebener C Code ist auch langsam. Momentan ist der Compiler nicht das Problem der Software Branche. Die müssen erst einmal lernen wie man Moderne Architekturen baut sicher und möglichst Fehlerfrei. Ich weiß schon das meine Meinung zum Thema nicht unbedingt bei jedem beliebt ist aber irgendwie gibt es zwar immer mehr Rechenleistung in den Geräten ohne das die einen brauchbaren Nutzen hat. Palm hatte mal eine Handschrifterkennung mit extrem wenig Rechenleistung umgesetzt. Heute hat man sehr viel mehr Rechenleistung in den Mobilen Geräten aber Handschrifterkennung ist praktisch nicht vorhanden. Man tippt auf einer Bildschirmtastatur die nicht mal so intelligent ist das sie sich an den User anpasst und schlecht getroffene Tipper korrigiert. Die meisten Menschen Tippen auf Touch recht konstant daneben was am Blickwinkel liegt. Bei Spracherkennung die bei Heutigen Rechenleistungen das Telefon erledigen kann wird aber die gesamte Sprache zum Google, Apple oder Amazon übertragen um diese auszuwerten. Die Liste kann man noch lange machen was alles auf Geräten ginge aber nicht gemacht wird weil die Betriebssystemhersteller die Rechenleistung lieber in Systeminternen ... was weiß ich ... versacken lassen als dem Kunden einen Mehrwert zu bieten.
Ist ja OpenSource daher darf man ja ändern und weiter veröffentlichen. Ja das mit github ist so Ok. Ist da dann so leichter einen Überblick zu behalten und man kann die Änderungen besser verfolgen.
es gab im Lauf der Zeit vom Pi A bis zum Pi3 B+ durchaus mal Umbenennungen bzw. Vertauschungen der GPIO Nummern.
wiringPi kann die GPIOs automatisch um-mappen, per eigener konstanter wiringPi Nummerierung, bei den BCM Nummern und den physikalischen muss man tatsächlich selber aufpassen - dessen Autor Gordon Henderson hat sich irgendwann dazu im raspi.org Forum geäußert, als die 3 verschiedenen Nummerierungstypen diskutiert wurden.
Seit dem B+ layout hat sich aber dann bei den GPIO-Nummern nichts mehr geändert.
Auch der Jessie device tree wurde irgendwann in 2016 abgeändert, was wiringPi intern berücksichtigt, je nach Raspbian distri.
Der spezielle auf den Pi abgestimmte Raspbian dev tree führt auch dazu, dass z.B. wiringPi auf dem Pi2 nicht auf der Raspi Debian distri ev3dev funktioniert.
Sogar bei UART gab es von Pi2 zu Pi3 eine Änderung, die erst für die GPIO-UART für alle libs per serial0 statt ttyAMA0 ersetzt und dadurch wieder vereinheitlicht und rückwärtskompatibel gemacht wurde - in alten libs muss man das selber patchen.
alexander_ro
19.11.2018, 13:44
... - in alten libs muss man das selber patchen.
Genau deshalb sollte man diese Hardware Abhängigkeiten nicht in eine Bibliothek packen. Der Linux Kernel ist hier mit dem Devicetree schon recht modern aufgestellt. Das ist vielleicht für Anwendungen zu aufwändig aber Port Zuordnungen im Code festzulegen ist böösseeee ... ;)
Das ist aber das gute an OpenSource wer das so möchte kann es so tun aber ich kann es anders machen.
Demnach würde wiringPi auf meinem Raspi unter Gentoo so nicht funktionieren. Ein guter Grund mehr warum die Entscheidung es nicht zu benutzen für mich richtig war.
Mit den verschiedenen Version hatte ich dann scheinbar einfach Glück das bei mir alles Kompatibel ist. Ich hatte bisher angenommen es lag daran das die Hardware Entwickler darauf geachtet hätten.
Das folgende ist ein früheres Experiment zu Software PWM. Das will ich noch in eine Klasse verpacken evtl. mit Unterstützung als Software Signal Generator. Dann könnte man Treppenspannungen, Sinus, Dreieck und Rechteck auch erzeugen. Die braucht man zum Entwickeln doch immer wieder mal. Die Frequenzen sind zwar nicht hoch aber die Software Kontrolle hat schon auch ihre Vorteile.
long timeOn = 1000;
long timeOff = 29000;
auto func = [&] ()
{
std::ofstream filePortValue ("/sys/class/gpio/GPIO11/value");
for (;;)
{
// Port ausschalten
strConfig = "0";
filePortValue << strConfig;
filePortValue.flush ();
// Zeit für "aus" abwarten
microSleep (timeOff);
// Port einschalten
strConfig = "1";
filePortValue << strConfig;
filePortValue.flush ();
// Zeit für "ein" abwarten
microSleep (timeOn);
}
filePortValue.close ();
};
std::thread t1 (func);
NumberFive
20.11.2018, 06:10
das C schnell als C++ habe ich nie gesagt. Und ich finde es Ok wenn C Programmierer weiterhin C machen auch das wurde Modernisiert und besser guten C Code als schlechter C++ Code.
Das die Spracherkennung Zuhause Funktioniert und nicht auf dem Gerät ist klar hat aber weniger den Grund der Rechenleistung der Mobileingeräte. Wobei wir hier noch das Thema alt Geräte ins Feld führen könnte.
Schon mal Probiert ein Modernes Smartphone mit 8 Kernen wirklich aus zu lasten und dabei in der Hand zu halten ? Auch der Akku hält das nicht lange durch.
Aber wir kommen zu Weit vom Thema ab. Versuchen wir unsere Software zu unseren Bedingungen zu machen und so die Welt ein bisschen besser. Nur rum Kriteln bringt uns alle nicht weiter.
Das einzige was mir echt zu denken gibt ist das Thema keine Zeit um Software machen zwar gibt es in immer mehr Sachen Software aber bei der Entwicklung wird 0 Zeit für die Software eingeplant. Software ist ja oft nur
Gentoo auf dem PI finde ich echt heftig den das Kompilieren auf der SD Karte mach doch nicht wirklich Spaß wie viele Karten hast du schon durch ?
Ich finde Debian schon ganz Ok und ich habe das auf Desktop und PI dann klappt es ganz gut mit dem Transfer der Software. Desktop Testen und dann auf den PI Portieren so weit nötig. Wobei ich fast nix habe was bis dato Portiert werden musste. Neu Compilieren natürlich.
NumberFive
20.11.2018, 08:31
Habe mal was in Richtung PWM gemacht leider kein OSSI da um zu gucken. Gefühlt dreht der Lüfter unterschiedlich schnell.
... - in alten libs muss man das selber patchen.
Genau deshalb sollte man diese Hardware Abhängigkeiten nicht in eine Bibliothek packen.
ich meinte es anders:
dir wird gar nichts anderes übrig bleiben, als es ebenso zu machen wie wiriningPi, denn es haben sich ja nun mal die GPIO-Nummern teilweise verändert, und der dev tree ebenfalls für die herausgeführten UART-GPIOs (z.B. der UART "Pfad" /devAMA0 ist ja nicht mehr wie früher auf den GPIOs, sondern wird ab Pi3 intern für BT verwendet - die GPIO UART heißen jetzt anders). wiringPi als lib prüft ja intern automatisch auf die aktuelle Hardware und die OS-Version, und kmpiliert dann entspr. abhängig.
Auch i2c0 und i2c1 haben eine Änderung erfahren von Pi A bis hin zum B+ design.
Wenn du also für verschiedene Pi-Plattformen kompilierst, muss du irgendwo in deinem Code die boardabhängigen dev Pfade reinschreiben, einmal so, und einmal so. Und für andere Plattformen wie BPi oder BBB oder gar Linux-PCs ebenso, erst recht.
alexander_ro
20.11.2018, 20:47
Die SD-Karten sind von Samsung und haben damit kein Problem. Für große Sachen ist der Raspi beim compilieren schon ein bisschen langsam. Würde man große Programme darauf Entwickeln ist das Störend aber so nicht der macht das ja alleine muss ich nicht darauf warten.
Ja man kann ein Smartphone mit 8 Kernen in der Hand halten ohne Brandblasen zu bekommen. Es wird deutlich warm das schon mehr nicht weil die CPU die Notbremse zieht wenn es zu warm wird. Sprache erkennen können die trotzdem. Braucht Strom keine Frage aber man braucht die ja nicht andauernd. Wäre aber immer noch besser als das ganze Leben an Ami Konzerne zu streamen.
Software PWM kann man vielleicht leichter Testen wenn man eine LED an den Port klemmt. Ich glaube Mensch erkennt Helligkeitsunterschiede leichter als Drehzahlunterschiede. Kann auch sein das die Frequenz für einen Motor zu hoch ist. Du musst ja drei Sachen einstellen die Grundfrequenz und das Tastverhältnis also ton/toff. Bei Software PWM stellt man das alles halt mit den Wartezeiten ein. Bei Hardware PWM wird die Frequenz ja aus dem Takt und dem gewählten Teileverhältnis eingestellt. Motore haben mit zu hohen Frequenzen Problem wegen der hohen Mechanischen Trägheit.
NumberFive
21.11.2018, 07:33
Zum Thema dev Pfade man kann es auch einfach in die Konfig packen für mich hat das nichts im Code zu suchen. Klar der Benutzer muss ein Gewisses Technisches Verständnis dann mit bringen aber mit Sample Config sollte es klappen. Warum sollte ich jemanden vorschreiben das die GPS Mouse an /dev/AMA0 hängen muss. Er könnte auch eine USB benutzen und dann heißt der Dev port anders.
Das mit der LED muss ich mal überlegen Thema ist halt die Belastung vom PIN.
Warum drei Werte vom PWM ja es sind 3 das richtig aber ich brauche ja nur 2 der Dritte ergibt sich immer. Mein source mach es so: Hz und ein wert zwischen 1 und 1000 damit stellst du die On Zeit ein in 0.1 % bis 100.0 % wenn ich meine Log Ausgaben trauen kann passt das dann auch. Vielleicht hat ein Bekannter auch mal Zeit würde mich schon Interessieren wie das auf dem OSSI aussieht was ich da mache.
Was ich auf jeden Fall noch ansehen muss ist das Thema CPU last das habe ich ganz vergessen.
alexander_ro
21.11.2018, 10:07
Logisch man muss das irgendwo einstellen wo welche Devicefiles zu finden sind. Nur wie schon oben geschrieben darf einem die Bibliothek nicht aufzwingen. Welcher Port, Timer oder Wandler was tut. Das ist Sache der Anwendung nur die kann wissen wie es am besten gemacht werden soll. Um es dem Anwender leichter zu machen kann man ja für alle unterstützten Platinchen eine Beispiel Konfiguration mit dazu geben. Die Bibliothek kann auch der Anwendung eine Funktion zum verarbeiten der Konfig mit liefern. Dann muss der Anwender kaum mehr tun und es ist trotzdem unter seiner Kontrolle welcher Port was tut.
Es ist so merkwürdig Raspi und Co wurden ja in erster Linie für die Ausbildung geschaffen. Das die ganzen Bastler die Dinger in Stückzahlen verbauen die keine Industrie zusammen bekommt war nie vorgesehen. Von dem Standpunkt ist es sogar schlecht wenn die Bibliothek alle Hardware Besonderheiten zu verbergen versucht. Jemand der Lernen will wie das Funktioniert und wie man es Anwendet muss schon mit bekommen wo die Hacken sind sonst ist die Ausbildung nicht vollständig.
Du hast doch einen Lüfter wie auch immer über den Port geschaltet dann kannst Du mit einem entsprechendem Vorwiderstand eine LED statt dem Lüfter anklemmen. Eine kleine Glühlampe aus einer Taschenlampe oder ähnlichem würde am Lüfteranschluss auch funktionieren. Eine LED ist aber mit einem passendem Vorwiderstand normal auch direkt an einem Port kein Problem. Du kannst den Widerstand aber einfach ein bisschen größer wählen dann wird die LED zwar nicht mit maximaler Helligkeit leuchten aber das ist zum testen auch nicht nötig. Sollte man dann halt in nicht zu heller Umgebung machen den Test.
CPU Last ist ja unter Linux leicht zu beobachten mit "top" zum Beispiel.
Die gesamte Last kann man mit "time ls" das zeigt dann vom ls die verbrauchte Rechenzeit an.
NumberFive
22.11.2018, 05:46
Ok jetzt müsste man definieren wo Lib und so anfängt und aufhört Natürlich wäre es falsch bzw komisch wenn jetzt zur Lib noch eine Konfig gibt. Da gehört es in den Lib aufruf. Ich hatte schon gedacht das das Nutzende Programm die werte weiter gibt. Schluss endlich sieht man das ja auch am Construtor deiner/meiner Klasse das hier der Pfad übergeben wird. Aber hier jetzt auch noch über "gutes" Design einer API zu Diskutieren wird Interessant den auch da gibt es nicht nur eine Meinung.
https://stackoverflow.com/questions/1221555/retrieve-cpu-usage-and-memory-usage-of-a-single-process-on-linux
Damit habe ich neben top die CPU Last an gesehen und was soll ich sagen nichts ergo kein Dummer drin.
Zum Thema LED Test:
Mein Problem ist die LED's die da sind habe ich keine Werte zu, den das war so ein Alles Drin pack von Vilros den ich mal zu Weihnachten geschenkt bekommen habe. Ergo kann ich den Vorwiederstand nicht ausrechnen an 5V. 5V Deshalb da ist ein TBD62083A zwischen PIN und Lüfter. Klar ich könnte jetzt wieder alles auseinander bauen und die LED am Pin direkt betreiben aber auch dann müsste ich nicht was das für eine LED ist.
Meine Elektronik Sammlung ist im Moment sehr bescheiden da ich lange nichts mehr gemacht habe und vor Jahren mal aussortiert habe weil habe ja eh keine Zeit...
Das ich noch mal Anfange hätte ich so nicht gedacht. Wollte ja nur mal eben eine CarPC bauen mit Standardteilen und jetzt sitze ich da und mache Unteranderem das hier und Controller Software (ATMega) fürs Netzteil.
Es ist so merkwürdig Raspi und Co wurden ja in erster Linie für die Ausbildung geschaffen. Das die ganzen Bastler die Dinger in Stückzahlen verbauen die keine Industrie zusammen bekommt war nie vorgesehen. Von dem Standpunkt ist es sogar schlecht wenn die Bibliothek alle Hardware Besonderheiten zu verbergen versucht. Jemand der Lernen will wie das Funktioniert und wie man es Anwendet muss schon mit bekommen wo die Hacken sind sonst ist die Ausbildung nicht vollständig.
da gebe ich dir völlig Recht -
nur leider wird C/C++ ja überhaupt nicht von der raspberrypi.org supportet, sondern, erbärmlicherweise, ausschließlich Python (sogar Adafruit bietet für seine Produkte nur Python Treiber für den Pi an, keine in C/C++, obwohl sie für Arduinos vorhanden sind) :( :( :(
- alles andere sind libs und Tools von ± Privatnutzern, die hier etwas für die Community zur Vereinfachung bereit gestellt haben 8)
(und GPIO-Steuerung samt deren dev trees ist ja auch nichts, was irgend etwas mit dem "normierten" C seit Kernighan und Ritchie oder Stroustrups C++ zu tun hat.)
alexander_ro
22.11.2018, 10:49
LED sind sehr ähnlich den größten Unterschied macht die Farbe. Da muss man nicht wirklich wissen was es genau für eine ist. Im Netz gibt es LED Rechner da wählt man die Farbe aus und bekommt brauchbare Werte vorgegeben. Man kann ja dann zur Sicherheit immer noch mit einem bisschen größeren Widerstand zum testen anfangen. Ein Labornetzgerät wäre da hilfreich aber nicht unbedingt nötig.
https://www.elektronik-kompendium.de/sites/bau/1109111.htm
Bibliotheken sind meist leicht zu erkennen weil sie eher allgemein gültige Dinge zur Verfügung stellen. Anwendungen sind dann die Teile die ein Bestimmtes Problem für den User lösen. Also eher spezielle Dinge. Aber ich sehe jetzt kein Problem warum ein Bibliothek keine Schnittstelle anbieten sollte um Konfig Dateien zu lesen. Logisch die sollte dann die Anwendung benutzen und wie Du schon meintest z.B. per Konstruktor an die Bibliothek übergeben. Aber mit der Bibliothek gelieferte Programm Beispiele könnten dann auch gleich ein Muster Config für die unterstützten Platinen auch anbieten.
Arduino C/C++ kann man aber gut als Beispiel benutzen um dann eine Version für den Raspi zu schreiben. GPIO ist auf jeder mit Linux laufenden Platine eigentlich nur ein Filesystem Zugriff. Abgesehen von den Namen der Devicefiles ist das auf allem mit Linux Kernel der gleiche Ablauf. C++ hat seit C++17 auch die Möglichkeit auf das Filesystem zuzugreifen. Mit fstream konnten ja Dateien schon immer gelesen und geschrieben werden. fstream kann man auch für die Zugriff auf Devicefiles benutzen.
https://en.cppreference.com/w/cpp/experimental/fs
(https://en.cppreference.com/w/cpp/experimental/fs)
Ich habe jetzt für meine I2C Klasse erst mal noch die Log Klasse fertig gebaut. Man muss jetzt zuerst ein Log Objekt erzeugen und beim Konstruktor der I2C Klasse mit übergeben. Je nachdem welche der Log Klassen man erzeugt ist dann das Log Ziel die Standard Ausgabe, eine Datei oder Syslog. Eine LogNoLog Klasse entfernt soweit möglich den Code aus der Klasse. Das erledigt die Optimierung des Compilers muss man natürlich dem Compiler sagen das er Optimieren soll.
https://git.hts-software.de/cgit.cgi/Athena-Api/tree/Log
https://git.hts-software.de/cgit.cgi/Athena-Api/tree/I2c
Arduino C/C++ kann man aber gut als Beispiel benutzen um dann eine Version für den Raspi zu schreiben. GPIO ist auf jeder mit Linux laufenden Platine eigentlich nur ein Filesystem Zugriff. Abgesehen von den Namen der Devicefiles ist das auf allem mit Linux Kernel der gleiche Ablauf.
Arduino C++ lässt sich schlecht als Vorlage zu Linux C++ libs benutzen, da die Arduino-Libs zu viele spezielle Arduino-Funktionen benutzen (i2c, UART, SPI, avrgcc, Arduino String, kein File system etc.) - das Umschreiben können nur Könner, ich z.B. nicht. Selbst wiringPi funktioniert völlig anders als Arduino Wiring. Aber manche Könner haben tatsächlich portierte Versionen geschrieben, ohne dass ich die aber auch nur annähernd verstehe.
alexander_ro
22.11.2018, 17:36
Ich glaube Du stellst Dir das schwerer vor als es ist. Das schwierige ist die Hardware Programmierung die erledigt aber der Kernel für Dich. Um ein I2C, SPI oder UART zu verwenden musst Du nicht wie bei Arduino (ohne Lib) in Hardware Registern herum schreiben das erledigt ja bereits der Kernel für Dich. Du musst nur das Devicefile öffnen und dann die Daten zu dem an der jeweiligen Schnittstelle hängendem Geräte schreiben. Ich vermute mal Du hast schon unter Linux Text in eine Datei geschrieben. Mit den Hardware Schnittstellen geht es genauso nur das der Text nicht auf der Platte oder SD-Karte landet sondern über die Schnittstelle beim angeschlossenem Gerät.
Das interessante in einem Treiber für einen I2C Chip wo z.B. nur ein Arduino C++ Treiber vorhanden ist ist nicht das wie die Daten über die I2C Schnittstelle kommen sondern welche Daten der zum Beispiel für eine Porterweiterung dem Chip sendet um den Port als Ausgang zu benutzen und ein-/ausschalten. Das kann man mit ein bisschen suchen schon herausfinden.
Ich glaube Du stellst Dir das schwerer vor als es ist. Das schwierige ist die Hardware Programmierung die erledigt aber der Kernel für Dich. Um ein I2C, SPI oder UART zu verwenden musst Du nicht wie bei Arduino (ohne Lib) in Hardware Registern herum schreiben das erledigt ja bereits der Kernel für Dich. Du musst nur das Devicefile öffnen und dann die Daten zu dem an der jeweiligen Schnittstelle hängendem Geräte schreiben. Ich vermute mal Du hast schon unter Linux Text in eine Datei geschrieben. Mit den Hardware Schnittstellen geht es genauso nur das der Text nicht auf der Platte oder SD-Karte landet sondern über die Schnittstelle beim angeschlossenem Gerät.
Das interessante in einem Treiber für einen I2C Chip wo z.B. nur ein Arduino C++ Treiber vorhanden ist ist nicht das wie die Daten über die I2C Schnittstelle kommen sondern welche Daten der zum Beispiel für eine Porterweiterung dem Chip sendet um den Port als Ausgang zu benutzen und ein-/ausschalten. Das kann man mit ein bisschen suchen schon herausfinden.
haha, naja, wenn du meinst...
Die Erfahrung zeigt, dass es die wenigsten hinkriegen, die so was brauchen... :p
ich werde dich mal ansprechen, wenn ich wieder mal einen Raspi Driver für ein Gerät suche, für das es nur Arduino Driver Libs gibt 8)
NumberFive
23.11.2018, 07:49
Ich habe jetzt für meine I2C Klasse erst mal noch die Log Klasse fertig gebaut. Man muss jetzt zuerst ein Log Objekt erzeugen und beim Konstruktor der I2C Klasse mit übergeben. Je nachdem welche der Log Klassen man erzeugt ist dann das Log Ziel die Standard Ausgabe, eine Datei oder Syslog. Eine LogNoLog Klasse entfernt soweit möglich den Code aus der Klasse. Das erledigt die Optimierung des Compilers muss man natürlich dem Compiler sagen das er Optimieren soll.
https://git.hts-software.de/cgit.cgi/Athena-Api/tree/Log
https://git.hts-software.de/cgit.cgi/Athena-Api/tree/I2c
Die Idee hier einen Logger zu übergeben ist ja super aber warum benutzt du eigene Loglevels ? Und nicht die die jeder Kennt Ok security kann ich mir noch ganz gut vorstellen das man das brauchen könnte.
Ich bleibe bei https://github.com/muflihun/easyloggingpp das Funktioniert für mich ausreichend und hat auch die Möglichkeit den Logger an eine so / dll weiter zu geben.
START_EASYLOGGINGPP(argc, argv);
if(utils::FileExists("loggerback.conf")) {
// Load configuration from file
el::Configurations conf("loggerback.conf");
// Now all the loggers will use configuration from file and new loggers
el::Loggers::setDefaultConfigurations(conf, true);
}
Und auch eine Möglichkeit eine Config als Datei zu übergeben. Also das was für eine Lib angesprochen wurde.
Das überall ein TestModul gibt finde ich ja super hast du dich mal mit UnitTest beschäftigt das ist was ich unbedingt noch machen will aber in C++ ist das nicht ganz so Easy wie mit C# und Windows.
Ich will die dann auch gleicht mit dem CMake script laufen lassen. Aber bis dahin ist noch ein weiter weg. Auch ein Build Server wäre Cool.
Aber jetzt erstmal auf Funktion Programmieren. Im Auto habe ich der Zeit nur ein Loch das auch nicht so doole.
Wenn ihr Lust auf Device Treiber habt:
https://www.adafruit.com/product/1983 das Fliegt hier noch rum ich hätte es gerne als "PiTFT as Raw Framebuffer Device" die Touch Funktion ist nicht unbedingt notwendig. Als Routen anzeige direkt vorm Lenkrad. Leider bekomme ich nichts zu sehen auf dem Display. Und müsste auch wissen welche Pins gebraucht werden den das man es auf Stecken kann nutzt mir gar nichts da ich es ja absetzen will.
Ja Träume habe ich viele aber so wenig Zeit und alleine ist es schon ein Monster Projekt.
alexander_ro
23.11.2018, 11:50
Ich kann schon helfen so einen Treiber um zu bauen aber ich mache das aber nicht alleine. Da muss der betreffende schon mit machen ... :)
Nur der Security ist ein eigener Loglevel die anderen benutzt der syslog. https://de.wikipedia.org/wiki/Syslog
Ich habe nur viel weniger davon als der Syslog. Man kann die aber ja relativ leicht noch ändern. Ich werde mal schauen wie ich mit denen zurecht komme.
Das geht zwar Richtung Unittest was ich da gemacht habe ist aber nur eine einfache Art weil mir jede Menge nötige Testfälle fehlen. Eigentlich habe ich das gemacht das jemand der so eine Klasse verwenden will zumindest einfache Beispiel hat wie das von mir gedacht war.
Da Du ein Debian als Basissystem hast würde ich an Deiner stelle Debian Pakete machen. Das was Du da für einen Build Server brauchst ist schon vom Debian Projekt gemacht worden.
Ich benutze das Orginal Raspi Touch Display. Darauf kann man mit OpenGL sogar 3D-Grafik ausgeben. Es belegt auch kaum zusätzliche Ports da es den eigenen Display Anschluß der Raspi benutzt (nicht den HDMI den anderen). Ein weiterer großer Vorteil ist das es ohne jede weitere Programmierung alles kann was man braucht. Ich benutze mit meinem noch eine Bluetooth Tastatur mit Touchpad. Dann kann man mit dem arbeiten wie mit einem normalem Computer. Sehr praktisch das ist ... :)
Wegen der OpenGL Ausgabe habe ich auch schon mal ein Beispiel Programmiert. Es kann nicht viel Rendert nur Text auf einer Fläche und kann Tastatur eingaben lesen. Das Programm kann man aber nicht Innerhalb einer anderen Grafischen Oberfläche starten. Man muss vom Desktop mit strg + alt + f1 zu einem Terminal wechseln und es da starten.
https://git.hts-software.de/cgit.cgi/Athena-Grafik/tree/
Ich schau mir das an mit dem Display von Dir aber das was Du willst geht nicht mit allen Displays.
<Edit>
Das Display ist doch für einen Raspberry gemacht. Wenn Du es an einer anderen stelle haben willst kannst Du es ja mit Kabel verbinden. Schaltplan gibt es soch auch dafür. Dort müsste stehen welche Ports benutzt werden.
</Edit>
NumberFive
23.11.2018, 19:20
Ich glaube du hast mich nicht richtig verstanden.
Wäre mir neu das Raspberry Display und HDMI gleichzeitig gehen. Open GL kommt ja von Graphik Chip und davon hat der PI nur einen. Ich will aber zwei Displays das kleine und das Große per HDMI. Wenn du den Schaltplan so gut verstanden hast kannst du mir ja sagen welche Pins ich brauche das "nur" das Display angeschlossen ist und die Hintergrund Beleuchtung. Tasten und Touch brauche ich nicht.
Da das aber nur ein nettes gimik ist muss das wohl warten. Wahrscheinlich passt das mit den anderen Sachen am GPIO eh nicht zusammen und muss neu gedacht werden. Ich brauche ja auch ein Paar für andere Dinge Drehgeber, I²C für die Relais, Serial für Netzteil. Ich habe schon Displays für den I²C gesehen vielleicht ist das ein weg. Aber da ist es ja auch nicht mit dem Display alleine getan da braucht man ja auch ein paar Chips drum rum.
https://github.com/adafruit/Adafruit_STMPE610
Wenn ich das richtig deute hat das Ding zwei Schnittstellen SPI und I²C
https://github.com/adafruit/Adafruit_ILI9341
Das müsste der Display Teil sein
Ich glaube nicht das es so einfach ist als Debian Packet auf genommen zu werden um dann die Infrastruktur mit nutzen zu können. Dafür ist das Zeugs viel zu unfertig. Wo ich noch keine Zeit für hatte sind die ganzen Public Build server die Nutzen kann vielleicht ist ja da was passendes dabei.
Bitbucket Pipelines (http://bitbucket.org/product/features/pipelines) ist auch so was und da da das Repos liegt sollte ich mir das ansehen aber 50 Minuten pro Monat sind halt auch schnell auf gebraucht.
alexander_ro
23.11.2018, 20:09
Ich benutze den HDMI nicht ich fand den auch schon immer Überflüssig vermutlich wollten die aber das man das Teil an einen Fernseher stöpseln kann. Das Original Display ist ja relativ groß. OpenGL muss nicht Hardware Grafik sein. Die OpenSource Version von OpenGL nennt sich Mesa3D und kann auch Software Simulation die ist halt langsam logisch.
Welche Version des Displays hast Du denn?
Aus dem Schaltplan kann man nicht genau erkennen was Touch und Tasten oder Display ist. Da wirst etwas experimentieren müssen. Was man aber erkennen kann ist welcher Anschluß des Displays mit welchem am Raspi verbunden ist. Es gibt Displays die eine serielle Schnittstelle haben die brauchen sonst keine Chips drum herum. Werden aber auch anders angesprochen also nicht als Framebuffer vom Linux Kernel. Ist halt eine Frage wie schnell es sein muss.
Das STMPE610 ist ein Touchscreen Controller die haben eigentlich immer eine serielle Verbindung. Das reicht um eine Reihe XY Positionen an die CPU zu senden. Das andere ist aber ein Display für einen Arduino. Wolltest Du das nicht an den Raspi anschließen?
Debian hat ja auch einen Entwickler Zweig ich meinte aber auch nicht als Paket bei Debian. Die Software die Debian zur Erstellung ihrer Pakete benutzen ist genauso OpenSource wie der Rest. Die kannst Du auch auf einem eigenen Rechner benutzen und damit ein Debian Paket erzeugen das andere dann einfach bei sich installieren können. Lohnt sich aber vermutlich erst wenn es eine gewisse Stabilität erreicht hat. Entwickler die es Testen sollen oder mit Entwickeln müssen so den Sourcecode haben und haben kein Problem das zu übersetzen.
Ich glaube nicht das ich Bitbucket benutzen würde. Vernünftig kostet es eine Menge Geld und sonst sind die Enschränkungen zu groß. OpenSource Projekte wenn pro User zahlen müssen kann das ganz schön teuer werden. Ich betreibe für einige als Entwicklungsrechner im Internet einen Raspi. Das läuft gut und kostet nicht viel und egal wie viele User es sind es kostet nicht mehr. Sollte mal das Team zu groß werden für einen Raspi kann man das leicht als virtuellen Rechner auf größere Server legen.
NumberFive
23.11.2018, 21:27
Also am HDMI hängt das Waveshare 7" bei dem PI den ich zur Display Test nutze ist es ein ganz Normaler Monitor also ein HDMI zu DVI Kabel ist glaube ich 19".
Die genaue Version von dem Adafruit 2,8" kann ich dir leider nicht sagen war auch ein Geschenk. Hinten steht STMPE610 und ILI9341 (https://github.com/adafruit/Adafruit_ILI9341) drauf wenn man den Offiziellen weg geht mit script wird auch ein Treiber names ILI9341 (https://github.com/adafruit/Adafruit_ILI9341)
geladen. Lade gerade noch mal ein ältere Version vom Debian runter weil auf der Seite steht sie habe mit der Getestet.
https://learn.adafruit.com/adafruit-2-8-pitft-capacitive-touch/easy-install-2
Habe aber wenig Hoffnung das es mich weiter bringt.
Ich denke so lange ich es alleine mache passt Bitbucket es gab bis jetzt erst einmal einen der ein bisschen was für das USB gemacht hat. Mal sehen wie wie sich das alles entwickelt. Bis jetzt habe ich nur immer gehört melde dich mal wenn es fertig ist oder mit Kodi und Navit geht es auch. Siehe https://raspicarprojekt.de/. Oder für was braucht man das kann mein Auto jetzt schon. In sofern sehe ich noch nicht die Gefahr das ich mehr als eine Datensicherung brauche. Ich träume halt oft vom richtig machen aber wenn man es genau nimmt für was ?
Das mit dem Internet Pi musst du mir bitte mal näher beschreiben ich verstehe das gerade nicht so wirklich.
witzig, die Adafruit Displays hatte ich auch sofort im Sinn, als ich die fehlenden Raspi C++ Treiber dafür ansprach.
Ich habe ein Featherwing 3,5" Touchscreen, und ich bräuchte tatsächlich den kompletten Funktionsumfang, inkl. Touch und Buttons und Zeichenfunktionen, per SPI.
https://www.adafruit.com/product/3651
Normale Ausgabe auf HDMI, aber zur Steuerung der Buttons mangels "Delphi for Raspbian" als 2. Display, mit allen Adafruit GFX, Touch, Fonts und Adafruit HX8357 Grafik-Funktionen.
https://learn.adafruit.com/adafruit-3-5-tft-featherwing/tft-graphics-test
soll ja so einfach sein, Arduino Libs auf den Raspi zu portieren :p
NumberFive
24.11.2018, 06:58
Also ich gebe mit dem Display auf entweder ist es Kaputt oder zu alt. Wüsste zur Zeit nicht was ich noch machen kann dem Teil ein Bild zu entlocken. Bzw prüfen soll ich finde keine Fehlermeldung.
https://www.adafruit.com/product/1601
https://learn.adafruit.com/assets/13040
Wie gesagt nur Zeichnen würde mir reichen.
Ich kenne jetzt die die Framebuffer Schnittstelle nicht aber wenn man da was drum macht zum Zeichen würde das glaube ich reichen und vor allem könnte man so ein Haufen einfacher Displays unterstützen.
https://github.com/notro/fbtft es sind ein haufen in den Linux Kernel gewandert. @HaWe vielleicht ist da auch dein Treiber dabei.
http://marcosgildavid.blogspot.com/2014/02/getting-ili9341-spi-screen-working-on.html
da hat einer erklärt wie es geht.
sudo fbi -T 2 -d /dev/fb1 -noverbose -a adapiluv320x240.jpg so kann man da ein Bild hin schieben so teste ich auch.
Wieder eine Nacht ohne vorwärts kommen bin schon ein bisschen frustriert...
alexander_ro
24.11.2018, 11:49
Ich kenne die Adafruit Displays nicht bisher habe ich von der Firma nie etwas gekauft. Wenn ich das richtig sehe auf den Bildern hat das einen zwei Stecker um eine Ecke angeordnet und das andere nur Stecker an einer Seite. Soll natürlich auch schon vorgekommen sein das ein Display kaputt ist das kann ich aber so auch nicht feststellen. Kannst Du vielleicht mal ein Foto von vorne und hinten irgendwo posten. Vielleicht finde ich ja einen Anhaltspunkt welches es ist.
Bei der Elektor haben die so einen Audio DAC gebaut für den auch ein Display. Das habe ich ganz Problemlos zum laufen bekommen. Musste nur den Kerneltreiber von der Internetseite installieren und einstellen. Dann zeigt er vom booten bis zum Desktop alles auf dem Display an und es geht auch der Touch.
https://www.elektormagazine.com/files/magazine/2017/dolo/Manual%20High%20End%20Audio%20DAC%20for%20Raspberr y%20Pi%202.pdf
auf Seite 13 ist der Link zum Displayhersteller.
https://www.waveshare.com/wiki/3.5inch_RPi_LCD_(A)#Driver
Wegen dem umschreiben der Treiber ging es aber oben nicht um ein Framebuffer Display Treiber. Das Problem ist nämlich nicht das Umschreiben sondern das es bei Arduino keine Framebuffer Devices gibt die sind Linux spezifisch. Also ist es kein Umschreiben sondern eine neu Entwicklung das ist etwas ganz anderes. Ich verstehe aber auch nicht warum man unbedingt ein Display benutzen muss das nicht kompatibel ist. Für den Raspi gibt es wirklich viele Displays die speziell für die Hardware gebaut sind. Man muss nur schauen weil manche der Displays parallele Schnittstellen haben und damit fast alle Ports belegen.
Der Internet PI ist einfache ein PI an einer Internetverbindung mit einer öffentlichen statischen IP-Adresse. Den kann man dann als Server im Internet benutzen für git, web, mail oder was auch immer. Wenn man nicht tausende User hat kommt der damit Problemlos zurecht.
Warum es in Deutschland so schwer ist jemanden zu finden der an einem Projekt mit macht ist eine andere Geschichte ich will das jetzt nicht näher ausführen weil es eine länger Geschichte ist.
NumberFive
26.11.2018, 05:20
Schade deine Meinung warum man keine Opensource Entwickler finde hätte mich jetzt schon Interessiert. Egal.
Um einfange GUI zu machen könnte man auch über Gimp, SVG Dateien nach denken. Und dann einen "Treiber" der das SVG auf dem Display zeichnen. Herausforderung an dem Punkt ist dann das erkennen wann jemand geclickt hat und auf was. Das kenne ich von meiner eigenen GUI Entwicklung das wir Irgend wann Tricki. Schluss endlich Funktioniert sie so das von der SDL einfach Zeichen Flächen zu Verfügung gestellt werden also Quasi Controls und so die GUI zusammen gebaut wird. Ich hatte am Anfang die Aberwitzige Idee ich könnte die GUI als Lib bauen und nebenbei mit entwickeln aber das habe ich schon lange auf geben.
An der Verzeichnis Strucktur kann man es noch erkennen aber das war's dann auch. Das Projekt wäre alleine nie zu machen.
https://behindthesciences.com/electronics/connecting-ili9341-SPI-TouchScreen-lcd-to-a-raspberry-pi-in-python/
Das ist Quasi so wenn ich das richtig verstanden habe das Display ist ein Bild und das wird dann "einfach" via SPI zu Display gesendet. Wenn man jetzt immer von einen Einfachen Bitmap ausgeht kann für die Graphic power auch auf so was wie Cairo oder so zurück greifen das muss man ja nicht selbst bauen.
Schade das du nicht verstehst das man an dem PI ein zweites Display gut brauchen kann. Bei mir geht es einfach um das Display welches bei machen Autos zwischen Tacho und Drehzahlmesser ist. Das dir sagt in 500m Rechts zum Beispiel. So das ich nicht den Blick auf das Große Display in der Auto Mitte machen muss.
Klar man könnte auch das ganze Armaturenbrett zum Display machen es gibt da auch geniale Lösungen von Geforce zum Beispiel oder gar ein Headup Display aber das ist nicht zu machen. Zu mindestens nicht für mich auch kommt dann schnell das Thema TÜV auf.
Eine zweite Anwendung wäre zum Beispiel am HDMI Leinwand und das Steuerdisplay als 3,5 Zoll am PI also ich denke da kann man schon bedarf erkennen.
Kodi drauf und so Media Wiedergabe ansteuern per Display und Ausgeben auf HDMI ok hier bräuchte man dann noch ein Kodi addon.
Der Elektor Link funktioniert bei mir nicht.
Zu mindestens bei mir geht es nicht um aufwendiges GUI und umleiten der Console oder sonst was. Ich möchte einfach was um "Bilder" anzeigen zu können. wenn ich HaWe richtig verstanden habe ist das sehr ähnlich nur möchte zusätzlich ein event wenn man mit dem Finger eine bestimmte Fläche Berührt.
Wir driften ordentlich von Thread Thema ab...
alexander_ro
26.11.2018, 12:14
Die Kurzfassung ist das Deutschland ein reiches Konsumland ist. Man hat es nicht nötig etwas selber zu machen. Das gilt zumindest für die Meisten und daher hat selber machen hier so einen arme Leute Beigeschmack. Was ja nun bei weitem nicht der Fall ist. Es gibt definitiv nichts Wertvolleres als ein Handgefertigtes Einzelstück. Es gibt Untersuchungen wo z.B. viele 3D-Drucker benutzt werden. Nicht besitzen sondern wirklich benutzen. Das ist nicht Deutschland interessanterweise sind es eher ärmere Länder. Bei denen werden dann damit Ersatzteile für Mensch und Technik gebaut. Es gibt hier auch Unterschiede in den Städten in Berlin die eher eine arme Stadt ist wird sehr viel gemacht. Dort findet man immer Leute die auch Mitmachen. München ist eher eine Reiche Industriestadt hier wird nur ganz wenig gemacht ... man hat es einfach nicht nötig und sitzt lieber jeden Tag vor der Glotze und lauscht dem Täglichen Fernseh Nonsens. Dabei geht es beim selber bauen nicht unbedingt darum billiger zu bauen sondern anders und besser als der Industrieschrott der sehr oft auf dem Markt ist.
Ich habe doch nie geschrieben das ich zwei Displays für unnötig halte nur das man den HDMI nicht braucht. Es bleibt ja dann immer noch der Anschluss an dem das Orginal Display angeklemmt wird und dann kann man beliebige Displays mit z.B. SPI verwenden. Eine GUI ist immer nichts anderes als ein Pixelbild zu dem verwaltet wird welche Regionen anklickbar sind. Was Du aber gar nicht selber machen und Programmieren musst da Du ja auf einem Linux Rechner arbeitest. Alles was Du brauchst ist einen Kernel Treiber für jedes Display. Der Kernel kann beliebig viele Displays verwalten. Du musst dem bei der Programmierung nur sagen wo die Ausgabe hin soll. Das sollte aber die von Dir benutzte SDL auch können. Man verwaltet das am leichtesten so wenn man so tut als sei alles ein Window auch Butten und so. Dann gibt es Windows die fixe positionen in anderen haben und welche die man verschieben kann.
Das der Elektor Link nicht geht kann sein das der im Mitgliederbereich ist. Aber das wichtige der Hersteller der Display mit funktionierendem Treiber hat habe ich ja extra angegeben.
Ich würde an zum anzeigen von Bildern die Möglichkeiten des Kernels nutzen. Die Programmierung wird dann unabhängiger und den Teil des Projekts pflegen andere für Dich.
NumberFive
26.11.2018, 17:16
Deutschland das Land der Dichter und Denker, Ingenieure...
Ok das mit dem Display habe ich jetzt auch verstanden. Wo bei ich sage den HDMI braucht man schon alleine wegen dem Sound und auch wegen der Auflösung das Waveshare hat 1024 x 600 Punkte also 16:9 nicht 4:3 aber egal. Mag ja sein das der Kernel beliebig viele Displays kann aber so einfach wie du schreibst ist es nicht. Ja die SDL kann auch mit einem Framebuffer Device um gehen aber eben nur mit einem Display.
Die SDL kann nicht einmal so und dann noch mal so zu mindestens nicht in einem Process. Und auch X-Server kann das nicht immer habe nämlich das Problem gehabt das ich zwei Monitore an meinen Rechner wollte und habe nach 2 Wochen aufgeben.
Ja Linux ist gut und kann viel aber eben auch nicht alles.
alexander_ro
26.11.2018, 17:54
Also mein Alien mit Gentoo kann das. Ich kann den internen Monitor und einen externen am VGA Port gleichzeitig benutzen. Der funktioniert dann als Verbreiterung des Desktop.
Bei den PC Grafikkarten muss es der Treiber unterstützen. Die kann man als Framebuffer Device benutzen sollte man aber nicht weil es dann keine Hardware Beschleunigung gibt.
Klingt für mich wie wenn es gehen könnte: https://stackoverflow.com/questions/18728821/multiple-displays-in-sdl2
<edit>
Man muss unterscheiden zwischen den alten X-Servern und den neuen die bereits auf der mit Wayland geschaffenen Infrastruktur arbeiten. Da hat sich in den letzten Jahre viel verändert und das macht die Informationen im Netz recht unübersichtlich weil man manchmal schwer feststellen kann von was der Autor schreibt.
Hier gibt es eine kleine Übersicht: https://de.wikipedia.org/wiki/Direct_Rendering_Infrastructure
</edit>
(https://de.wikipedia.org/wiki/Direct_Rendering_Infrastructure)
NumberFive
26.11.2018, 20:20
Selbst wenn das wirklich gehen würde was ich noch nicht glaube genau wegen der Treiberschicht das eine ist der Nativtreiber für den PI von der SDL der andere wäre der "Einfache" Framebuffer Treiber. Und das es ein Problem gibt sieht man ja sonst würde es den Eintrag ja nicht geben.
Klar kann es sein das ich das Problem habe das die zwei Grafikkarten von Treiber her nicht vertragen und es deshalb nicht ging. Aber Ergebnis ist das selbe. Auch möchte ich nicht wissen wie Langsam das alles wird wenn ich den X-Server dazu zwinge in den FB Modus zu gehen.
Ich denke man muss schon unterscheiden Meldet ein Treiber 2 Monitore oder habe ich 2 Treiber an 2 Monitoren.
alexander_ro
06.12.2018, 11:50
Für den Kernel ist es ein Unterschied ob zwei Monitore an einer Grafikkarte oder zwei Grafikkarten mit je einem Monitor. Auch ob es ein einfacher Framebuffer ist oder echte Grafikkarte mit Hardwarebeschleunigung. Aber für den Anwender macht es keinen Unterschied. An dem Display das Du z.B. über SPI anschließt kannst Du OpenGL 3D Grafik ausgeben. Das ist halt langsamer aber es geht. Mesa unterstützt OpenGL auf einfache Framebuffer Devices.
Ist zwar schon älter aber immer noch richtig: https://www.linuxwiki.de/FrameBuffer
Warum hast Du eigentlich in Deiner I2C Klasse das schreiben/lesen der Daten nicht mit read/write gemacht sondern direkt mit der Kernel Schnittstelle. Hat das irgendwelche Vorteile?
Ich habe an meiner weiter gebaut ist aber noch nicht so wie ich es haben wollte. Aber wie ich gesehen habe hast Du das ja schon selber erledigt dann kann ich mir ja Zeit lassen.
NumberFive
07.12.2018, 07:00
Zum Thema Monitore habe wir einfach sehr Unterschiedlich Meinungen / Erfahrungen. Ich sage nicht das es falsch ist was du sagst ! Wenn ich jedoch so ein einfacher Display habe möchte und das was es gibt ist vom Andrio zum Beispiel dann kann ich es einfach direkt an bin als zu waren das mir jemand ein FB Treiber schreibt. Klar dann funktioniert die Software nur genau damit.
Zum Anderen ich kann dir nur sagen wie es war mit 2 Graphickarten immer nur eine Aktiv mit eine Dual Karte sofort beide Monitor mit Bild.
Zum I²C und Kernel Funktion da will ich ehrlich sein das habe ich gefunden und es Funktioniert. Es mit den C++ Funktionen zu schreiben habe ich einfach nicht Probiert.
Ich habe am 15. einen Termin und möchte ich halten drum muss ich zur Zeit massiv auf Funktion Programmieren was sicher nicht nur Gut ist für die Software.
alexander_ro
18.12.2018, 12:32
Jetzt habe ich das mit dem I2C soweit fertig. Da momentan nur den LM75 Temperatursensor mit I2C habe gibt es auch nur für den eine Klasse zur Hardware Unterstützung. Ich habe mir ein Platinchen bestellt mit einem 16-bit Wandler auch mit I2C dazu werde ich jetzt mal noch so eine Hardware Klasse bauen. Ich habe wieder wie immer die ungeliebte Fehlerbehandlung eingebaut. Ich finde es halt sehr lästig wenn es Fehler gibt und das Programm schweigt sich darüber aus wo er aufgetreten ist ... :)
https://git.hts-software.de/cgit.cgi/Athena-Api/tree/I2c
Ja stimmt schon es kommt darauf an was man mit den Displays machen will. Wenn es ein Linux Rechner ist suche ich halt nach Möglichkeit eines zu finden das vom Kernel unterstützt wird.
NumberFive
19.12.2018, 08:48
Ich finde es halt sehr lästig wenn es Fehler gibt und das Programm schweigt
Da kann ich dir nur zustimmen noch besser sind try catch die alles fangen und nichts sagen.
Sieh ganz nett aus dein Code.
pIntLog->setLogLevel ("Debug");
pIntLog->sendMessage ("Call: I2c::I2c ("" + strIntDevFile + "", ..., pLog)");
Daran werde ich mich so schnell nicht gewöhnen aber das ist Künstlereiche Freiheit LOG(DEBUG) << "Da ist eine Debug ausgabe" finde ich da einfacher. Auch ist für mich das Loglevel kein String sondern ein enum.
alexander_ro
19.12.2018, 11:09
Ich wollte der Log Klasse noch einen Stream operator dazu bauen damit man den dann wie den std::cout benutzen kann. Man könnte dann den Loglevel mit einem Streammanipulator einsetzen. So was wie zum Beispiel den std::hex.
pIntLog << hts::debug << "Ganz wichtige Meldung"
Das wäre dann glaube ich schöner aber das kann man ja immer noch machen. Es gibt vieles das ich an meinen Klassen gerne noch anderes machen würde aber kann man leider nicht alles auf einmal machen. Wie man diese Streammanipulatoren baut muss ich mir auch erst noch mal anschauen. Die Variante mit den Funktionen schadet auf jeden Fall nicht wenn die in der Klasse vorhanden ist. Die enum finde ich nicht so gelungen sparen aber speicher das stimmt schon. Ich müsste dann in der Klasse eine Übersetzung machen zwischen dem enum und dem Log-Status der ein String sein muss oder ein Array. Bei mir werden nicht einfach alle Level unter dem in Log-Status angegebenen ausgegeben sondern man muss jeden angeben den man im Log haben möchte. Ausnahme ist wenn man alle haben will dafür habe ich den Log-Status on der alle Loglevel an das Logziel schreibt.
NumberFive
21.12.2018, 14:10
es gibt noch einen Vorteil den man in meine Augen nicht unterschätzen darf. String vergleiche sind Teuer. Wenn das Level ein Enum ist kann man es mit Int vergleichen was viel Weniger kostet. auch ist es leichter zu sagen Verbose = Alles. Sonst muss du bei Loglevel Verbose eine Menge If's mache alle auf Strings und das wird man merken. Klar das Merkt man sicher nur wenn das Logging auf Off oder Error sitzt. Wenn das Level auf Debug ist wird der Unterschied nicht so Dramatisch sein weil das schreiben dann mehr Zeit frist.
Aber es ist deine Software aber so machen es Alle logging Frameworks die ich bis jetzt in der Hand hatte.
alexander_ro
21.12.2018, 16:46
Wie viele Byte belegt denn ein enum?
Dafür sehe ich aber auch im Debugger gleich am Inhalt der Variable was Sache ist. Bei den enum wird immer nur eine Zahl angezeigt was die Bedeutet muss man dann suchen. Klar muss man vielleicht ein paar Byte mehr belegen. Die 64bit Prozessoren können aber so nur acht Byte auf einmal effizient vergleichen bei 32bit sind es immerhin 4 Byte. Klar können die auch ein Byte vergleichen aber das spart nicht wirklich Zeit. Normal findet das ja nur statt wenn etwas nicht nach Plan läuft alleine das nicht nach Plan laufen kostet schon Zeit. In Zeitkritischen Programmen sollte man so keine Ausgaben machen. Es ist auch ein Vorteil der Exceptions das die nur Zeit kosten wenn sie auftreten das gilt auch für die zur Behandlung nötigen Log Ausgaben. Stimmt aber schon es könnte in der Tat ein wenig Zeit und Speicher kosten viel wird es aber nicht sein.
NumberFive
23.12.2018, 10:59
ich habe mir jetzt nicht den Assembler Code für String vergleiche an gesehen und muss dir glauben das der Processor da mehrere Zeichen gleichzeitig vergleichen kann. (Wäre echt mal Interessant sich das in der Tiefe anzusehen).
Tatsache ist aber das für das Wort "Debug" ein 32 Bit Processor nach deiner Aussage schon nicht mehr reicht. Mir ist auch ein Rätsel wie du es machen willst wenn ich das Level auf Debug stellen das dann die Anderen Levels raus geschrieben werde ohne das ein if grab daraus kommt. If Level < Loglevel:DEBUG finde ich irgendwie einfacher zu lesen.
Auch wenn man jetzt eine Funktionsbeschreibung per Intellisence bekommt ist doch besser da steht als Type Loglevel als String oder Int da weiß man gleich was man da nehmen muss.
Also der Debugger unter Window Zeigt mir dann auch die Enums bei Linux sieht man es mal und einmal nicht habe noch nicht raus bekommen woran das Liegt.
enum class AppEvent : Sint32{
ChangeUiState,
CloseButtonClick,
PlayButtonClick,
MusikStreamStopp,
MusikStreamError,
MusikStreamPlay,
AlbenClick,
TitelClick,
PlaylistClick,
FilelistClick,
CloseGuiElement,
NewGeopos,
BackendConnected,
BackendDisconnected,
MapMenuOpen,
LongClick,
Click,
ClosePopup,
OpenMapTextSearch,
MediaFileUpdate,
RemoteControl
};
std::ostream& operator<<(std::ostream& os, const AppEvent c) {
switch (c) {
case AppEvent::ChangeUiState: os << "ChangeUiState"; break;
case AppEvent::CloseButtonClick: os << "CloseButtonClick"; break;
case AppEvent::PlayButtonClick: os << "PlayButtonClick"; break;
case AppEvent::MusikStreamPlay: os << "MusikStreamPlay"; break;
case AppEvent::MusikStreamStopp: os << "MusikStreamStopp"; break;
case AppEvent::MusikStreamError: os << "MusikStreamError"; break;
case AppEvent::AlbenClick: os << "AlbenClick"; break;
case AppEvent::TitelClick: os << "TitelClick"; break;
case AppEvent::PlaylistClick: os << "PlaylistClick"; break;
case AppEvent::FilelistClick: os << "FilelistClick"; break;
case AppEvent::NewGeopos: os << "NewGeopos"; break;
case AppEvent::BackendConnected: os << "BackendConnected"; break;
case AppEvent::BackendDisconnected: os << "BackendDisconnected"; break;
case AppEvent::MapMenuOpen: os << "MapMenuOpen"; break;
case AppEvent::LongClick: os << "LongClick"; break;
case AppEvent::Click: os << "Click"; break;
case AppEvent::ClosePopup: os << "ClosePopup"; break;
case AppEvent::OpenMapTextSearch: os << "OpenMapTextSearch"; break;
case AppEvent::MediaFileUpdate: os << "MediaFileUpdate"; break;
case AppEvent::RemoteControl: os << "RemoteControl"; break;
default: os << "AppEvent not in list";
}
return os;
}
Das man Kritische Processe nicht Loggen können muss kann ich nicht nachvollziehen. Ich Arbeite mit Systemen die 365/24 zu Verfügung stehen sollten und wenn das mal nicht so ist wollen alle wissen was war. Da haben mir die Log schon hofft wertvolle hinweise geliefert. Auch ist es so das ich die anzubinden Systeme nicht einfach ins Büro holen kann und für jeden neue Anbindung in der Welt rum fahren ist meinem Arbeitgeber schnell zu Teuer (mache ich auch nicht mehr gerne) ergo bleibt nur das Logging.
Aber lassen wir das du machst deine Software ich meine. Gerade bei C++ gibt es nicht nur eine Lösung für eine Sache und da spiele ganz schnell auch noch andere Sachen mit rein (Umgebung, Testbarkeit).
Eine Frage habe ich aber doch noch hast du dich schon mal damit beschäftigt wie man bei einer Exception in C++ an einen CallStack ran kommt ? das ist für mich der einzige echte Vorteil von C# oder Java.
alexander_ro
23.12.2018, 12:45
Der 64 Bit Prozessor arbeitet am schnellsten wenn er 64 Bit Wörter vergleicht. Dafür gibt es auch entsprechende Befehle die auch für String vergleiche taugen. Bei kurzen Strings und einem 32 Bit enum wird der Unterschied daher in der Schnelligkeit nicht so groß sein. Der gcc kann Dir den Assemblercode zugeordnet zu den C++ Sourcecode ausgeben. Da findet man das dann relativ leicht was er daraus macht. Erklärungen zu den Assembler befehlen findet man bei ARM.
Wenn Du bei mir als Logstatus Debug angibst dann wird nur Debug ausgegeben. Wenn Du Debug und Error ausgeben willst musst Du auch beides angeben. Die Log Klasse hat einen Logstatus (was soll ausgegeben werden) die LogMeldung einen Loglevel (Priorität diese Log Meldung). Das soll so sein. Logisch muss man einen if machen den muss man aber bei einem enum auch machen.
Der Linux Debugger macht das nur wenn er entsprechend konfiguriert wurde. Früher konnten die das gar nicht.
Du hast jetzt einfach die Zeit bei dem Kritisch unterschlagen ... :)
Zeitkritische Programmteile sollten kein Log ausgeben. Jedes Log auch vom syslog ist sehr teuer was Zeit betrifft.
Du hast da sicher recht das die Verwendung eines Strings ein bisschen Zeit kostet. Fast immer wird aber die Log Meldung so nur im Fehlerfall ausgegeben. Sehr oft für der Fehler zum sofortigen Programm Abbruch. Ich war aus Sicherheitsgründen schon immer der Meinung ein Programm sollte im Fehlerfall Infos Sammeln ausgeben und sich möglichst anständig beenden. Wobei ein exit schon problematisch ist weil dann keine Destruktoren mehr aufgerufen werden.
Wie sieht das denn mit dem Callstack bei den anderen aus?
Wenn ich einen brauchte habe ich den gdb bemüht. Des Programm starten zum Beispiel einfach bis zum Absturz laufen lassen. Dann kann man sich einen Callstack ausgeben lassen. In der Ausgabe des strace kann man den verfolgen. Oder wenn man die Erstellung eines Dump einschaltet kann man mit gdb diesen öffnen und ebenfalls den Callstack anzeigen lassen. Im Ideal Fall kann man es aus den Log Meldungen sehen.
NumberFive
26.12.2018, 09:55
Sorry aber das man mehr als ein Loglevel angeben muss geht wirklich an allem vorbei was ich so kenne. Normal gebe ich das Max an was ich sehen will.
Um ein Programm bis an den Punkt des Absturtz laufen lassen zu können brauche ich entweder gute User oder ein haufen log. Ich kenne nur immer wieder die Aussage Was hast gemacht als es Abgestürtzt ist ? Nichts ist einfach abgestürzt. Im Job Kontext sind jetzt gerade am Testen das immer Intern das Debug Level an ist aber nur bei Auftreten von einer Warn oder Error eintrag der Speicherbuffer geschrieben wird. Da kostet zwar Ram aber man kann sehen was kurz vor der Warn oder Error Meldung war ohne die ganze Zeit die Platte als Bremse zu haben. Wenn wir davon ausgehen das Logging nicht in eine Datenbank geschrieben wird was sich Natürlich in einfachen Systemen einfach nicht lohnt. Bei größeren Systeme schon aber das habe ich im Job leider noch nicht durch setzten können (im Job).
Bei den Dingen die Ich programmiere ist das Laufen lassen bis zum Crash definitiv nicht möglich weil wie gesagt andere Programme / Hardware die "User" sind und die sind nicht Transportiert bar.
https://tuxthink.blogspot.com/2012/07/printk-and-console-log-level.html
https://www.linuxquestions.org/questions/slackware-14/log-level-of-crond-273547/
https://logging.apache.org/log4cxx/latest_stable/apidocs/classlog4cxx_1_1_level.html
Loglevel immer Int
alexander_ro
26.12.2018, 10:32
Ich habe nie behauptet meine Log Klasse würde sein wie andere wäre sie das wäre es nicht sinnvoll eine neue zu bauen. Mich hat das schon oft genervt das man oft Loglevel einschalten muss die ich nicht haben will nur weil der zwischen den anderen liegt. Also ich will genau das sehen was für den Zweck wichtig ist und sonst nichts. Das macht das Log nur unübersichtlich und das wichtige wird dann übersehen. Da helfen Tools zum Auswerten auch nur bedingt.
Wenn man in Programmen Fehler sucht die andere Testen sollte man einen Speicherdump erzeugen lassen. Dann kann man ganz leicht die Ursache der Problems finden. Hat man seine Hausaufgaben gemacht bei der Fehlerbehandlung ist das aber fast nie nötig weil dann in der Log Meldung steht was wo passiert ist. Das einzige was sich etwas Widerborstig anstellt sind Speicherlecks aber für die Problemfälle unter den Problemfällen gibt es den Dump. Auch die Nutzung der Compiler Makros die einem Programmzeile und Dateiname in eine Log Meldung schreiben können sind von echtem Wert beim Fehlersuchen. Das Programm mit strace starten kann man auch für andere User einrichten und die Ausgabe liefert weitere Infos die helfen können. Sollte ein Programm sich nur Aufhängen und nicht Abstürzen muss man sich zwar zu dem User hin bewegen kann aber dann mit dem gdb auch einen noch laufenden Prozess Debuggen. Das ist immer sehr hilfreich wenn ein Programm hängt und keinerlei Kommentar abgibt was schief läuft. Also Möglichkeiten an Informationen zu kommen gibt es viele da sind die eigen Debug Meldungen nur ein kleiner Teil und oft nicht hilfreich weil die letzten Meldungen vor aufhängen/Absturz so nicht mehr im Log auftauchen.
Ja aber selbst ein int ist schon viel zu groß für die paar Loglevel ... :)
Powered by vBulletin® Version 4.2.5 Copyright ©2024 Adduco Digital e.K. und vBulletin Solutions, Inc. Alle Rechte vorbehalten.