Beiträge von superelchi

    Ja, das hab ich auch schon bemerkt. Das Abschalten des Plugins passiert - wen wunderts - im Plugin. Graphlcd-base kriegt davon (soweit ich das beurteilen kann) nix mit. Da der Treiber aber beim Erstellen das USB-Port, an dem das Display hängt, für andere Prozesse verriegeln muss um darauf zuzugreifen und von dem Abschalten des Plugins nix mitbekommt...
    War mit ein Grund, warum ich dieses CONNECT-Zeugs geschrieben habe (XBMC lässt grüßen). :D



    EDIT: Vielleicht sollte man beim Abschalten des Plugins alle Treiber dis- und beim Anschalten wieder connecten.


    Gruß
    superelchi

    Einer geht noch:


    hier ein Patch (naja, eigentlich ein re-write) von plugin.c zur Unterstützung von bis zu vier unterschiedlichen Display. Unterschiedlich soll heißen, dass ein Displayname aus der graphlcd.conf jeweils nur einmal vorkommen darf. Dazu hab ich die Syntax der Aufrufparameter etwas erweitert:

    Code
    -d, --display=DISP[,DISP]... use display DISP for output or if DISP=none use no display on startup
    -s, --skin=SKIN[,SKIN]...    use skin SKIN (default is "default")


    Beispiel: "serdisp" Display mit Skin "testskin", "image" Display mit Skin "default" und "ax206dpf" Display mit Skin "touchcol" wäre:

    Code
    -d serdisp,image,ax206dpf -s testskin,,touchcol
    oder
    --display=serdisp,image,ax206dpf --skin=testskin,,touchcol


    Außerdem kann man auch "none" als Display angeben, dann kann der Anschluss später über CONNECT gemacht werden.


    Über "CONNECT displayname [skin]" kann man weitere Display nachträglich anhängen (Achtung: wenn skin nicht angegeben ist wird "default" verwendet!), über "DISCONN displayname" ein Display entfernen oder über "DISCONN ALL" alle Displays auf einmal.


    Bis alle Displays was anzeigen kann etwas dauern, da beim Start ein Display nach dem anderen connected wird. Geht leider nicht anders, da der Skin-Parser nicht multi-thread fähig ist (ne Menge static Vars).



    EDIT: Was noch nicht konsequent umgesetzt ist, ist die Geschichte mit den externen Variablen (svdrp Befehle GET / SETEXP / UNSET / GET). Da die Vars im Display-Objekt gespeichert werden, sind die weg wenn das Display disconnected wird und neue Connects erhalten früher gesetzte Vars nicht. Die sauberste Lösung wäre meiner Meinung nach, die Verwaltung vom cExtData aus cGraphLCDDisplay in ein eigenes Singleton-Objekt zu verlagern. This is left as an exercise to the reader :D .
    (Heißt das überhaupt "Singleton" in C++? Muss immer mental unter lautem Fluchen und unter absingen obszöner Lieder von Java auf C++ umschalten...)


    Gruß
    superelchi

    btw. kann ich im laufenden Betrieb das skinfile nach Änderungen neu einlesen? - ist blöd wenn du jedesmal den vdr neu starten musst... Beim graphtft kann ich das über ein svdrpsend Kommando

    Wenn Du meine Patch von hier nimmst, geht das im laufenden Betrieb über

    Code
    svdrpsend plug graphlcd CONNECT ax206dpf


    Damit wird das Display - wenn es schon angeschlossen war - dis- und gleich wieder connected. Das ist wie ein Restart, Skin wird neu eingelesen.


    Gruß
    superelchi

    Übrigens ist es technisch möglich, das Plugin beim anstöpseln des Displays automatisch umzukonfigurieren auch ohne den VDR neu zu starten. Beim Boot funktioniert das dann natürlich sowieso. Ich habe das schon mal ausprobiert. Ich lade das graphlcd-Plugin mit Hilfe des Proxy-Plugins. Sobald udev das Display erkennt wird das graphlcd-Plugin mit neuer Konfiguration geladen. Die Frage ist, ist das überhaupt sinnvoll und wenn ja, was machen, wenn mehrere Displays angestöpselt werden.

    Das hat mit keine Ruhe gelassen. Ich hab mich heute nachmittag mal hingesetzt und dazu was zusammengestrickt. Zwei neue SVDRP Befehle: CONNECT und DISCONNECT. Damit kann man das Display über SVDRP wechseln. Ist noch nicht ganz sauber - aber kann das mal jemand mit mehreren Display testen? Bei mir gehts mit dem Pearl-Display und simlcd prima.


    Gruß
    superelchi

    Danke für die Hinweise, ich habe die Pakete korrigiert. Die Fonts werden jetzt alle installiert und die Gruppe im udev rules file habe ich angepasst. Ich bin mit der Gruppe lp nicht so glücklich, weil mir die Gruppe vdr besser gefällt, aber da das display ja eventuell auch ohne vdr benutzt wird, habe ich es jetzt mal so übernommen.

    Das mit "lp" war ja auch nur die schnelle Lösung. User "vdr" wird ja beim Installieren von vdr-plugin-graphlcd zu dieser Gruppe hinzugefügt. Sauberer wäre wohl das Anlegen einer neuen Gruppe wie "graphlcd" oder "libusb" zu der "vdr" dann hinzugefügt wird. Btw: wäre es nicht sinnvoll der udev-rule auch einen Namen wie "XX-graphlcd-usb.rules" oder "XX-libusb.rules" zu geben, da es ja wohl für alle USB-Displays gilt, die über libusb angesprochen werden?
    Und wenn ich schon nerve: in debian/links vom vdr-plugin-graphlcd können die ersten beiden Links auf Vera*.ttf raus, wenn Du das ganze graphlcd/fonts Verzeichnis kopierst.


    Gruß
    superelchi

    okay, habs mir mal angesehen.
    Probier mal das:
    /etc/vdr/plugins/plugin.graphlcd.conf muss so aussehen:

    Code
    -c /etc/graphlcd.conf -d ax206dpf -s touchcol


    Außerdem scheinen noch ein paar Fonts zu fehlen, also:

    Code
    apt-get source vdr-plugin-graphlcd
    cd vdr-plugin-graphlcd-0.1.9+git20110811/graphlcd/fonts
    cp DejaVuSans* /usr/share/vdr-plugin-graphlcd/fonts/


    Als letztes noch die udev-Regel in /lib/udev/rules.d/ax206dpf.rules anpassen, muss so aussehen:

    Code
    SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_device", MODE="0664", GROUP="lp"


    Statt GROUP="lp" kannst Du jede Gruppe nehmen, in der "vdr" Mitglied ist.
    Danach am Besten nochmal neu starten und freuen.


    Gruß
    superelchi


    EDIT: Tippfehler beseitigt
    EDIT2: Pfad für Fonts korrigiert

    Kurzer Zwischenstand der Entwicklung: der Treiber kann jetzt bis zu 4 Displays ansteuern, die beliebig angeordnet werden können. Also z.B. 2-4 Stück nebeneinander oder 2-4 Stück untereinander oder ein 4er-Block (2h x 2v, das ist dann eine Auflösung von 640 x 480). Alles jeweils entweder im Portrait- oder Landscape-Modus. Bevor einer fragt: klar, das Gehäuse stört und vier in einer Reihe ist Overkill. Aber die Unterstützung von 4 Displays war der selbe Aufwand, wie wenn ich nur 2 gemacht hätte. Wenn ich Zeit habe, mach ich mal ein paar Bilder.
    Ein Problem hab ich noch: da alle Displays die gleiche VID/PID haben gibt es keine Möglichkeit sie zu unterscheiden. Wenn die Displays am selben Hub (= Bus) hängen, ist es Zufall in welcher Reihenfolge sie erkannt werden. Ich habs so gelöst, dass ich jedes Display an einen anderen Bus hänge. Dann bleibt die Reihenfolge bei mir gleich auch wenn zwischendrin ein Display aus- und wieder eingestöpselt wird. Weiß da jemand eine sauberere Lösung?


    Was jetzt noch kommt ist Hot Plugging um das Display auch dann zu erkennen, wenn es erst nach dem Start von VDR eingesteckt wird. Mal sehn, vielleicht am WE oder Anfang nächste Woche...


    Gruß
    superelchi

    Sag das mal den anderen Treiberentwicklern. Etwa 1/3 der Treiber machts mit einem zweiten Buffer.

    Muss mich hier mal selber korrigieren, wenns sonst keiner tut: das ist natürlich absoluter Blödsinn! Typischer Fall von Betriebsblindheit - war viel zu sehr mit meiner Dirty-Rectangle Sache beschäftigt. In den anderen Treiber werden nicht Pixelbereiche sondern einzelne Pixel an das jeweilige Display übetragen. Da ist der Einsatz eines Doppel-Buffers zum Rausfiltern der Pixel vollkommen in Ordnung. Also: große Entschuldigung an alle Doppel-Buffer Treiberentwickler! Ihr seid genial! Und natürlich ein dreifach donnerndes HELAU! für den Entdecker der Doppel-Buffers!


    Gruß
    superelchi

    wozu 2 buffer?
    einer reicht vollkommen, dazu noch bounding box, was sich geaendert hat ('dirty region') und beim refresh nur das innerhalb der bbox uebertragen. fertig.

    Sag das mal den anderen Treiberentwicklern. Etwa 1/3 der Treiber machts mit einem zweiten Buffer. Ich habs inzwischen auch ohne hingekriegt.
    Ergebnis beim Bewegen des Cursors im Menü einen Menüpunkt runter: vorher: Anzahl geänderte Pixel = 76.800, nachher: Anzahl geänderte Pixel = 284.


    Gruß
    superelchi

    Kann es ein das mein blinkender Doppelpunkt in der Uhrzeit oben links dann die Sache komplett verlangsamt wenn z.B. der Sendungsname scollt? Weil dann das dirty-Retangle unnötig aufgebläht wird.

    Genau! Ich wust es schon immer: alles was blinkt ist schlecht. :D


    Kann man nicht in SetPixel das Pixel direkt zum Display schicken wenn es sich geändert hat?

    Weiß nicht ob das so gewollt ist. Was ich so in den bestehenden Treibern gesehen habe, wird in SetPixel() nur gesammelt und in Refresh() ans Display übertragen.


    Oder können hier nur grössere Bereiche in einen Rutsch gesendet werden und der Protokolloverhead für das Pixelweise setzen wäre zu groß?

    Der Hack für das Pearl-Display hat einen Blit-Befehl mit dem man ein Recheck von Pixeln auf einen Rutsch überträgt.


    du meinst die CPU hat viel zu tun dadran? Oder das glcd? Ersteres ist egal, da eh nur am langweilen, Letzteres ist natürlich sehr interessant, da dann ja sehr viele Daten zu übertragen sind!

    Mag sein, dass sich die CPU freut wenn sie was zu tun hat. Aber ich hab in grauer Vorzeit auch mal Embedded-Entwicklung gemacht und wenn ich dann sowas sehe, zieht sich bei mir alles zusammen. Und mal eben einen zweiten Buffer von 320 x 240 Pixel x 2 bpp macht auch schon schlappe 150 KB zusätzliche unnötige Speicherbelastung.


    Gruß
    superelchi

    Ja, der t6963c-Treiber macht es genau so. Alles was über SetPixel() kommt in einen Buffer schreiben und in Refresh() mit den Daten des letzten Refreshs vergleichen. So werde ich es wohl auch machen müssen. Ändert aber nichts daran, dass wenn sich z.B. beim Springen im Menü nur der Cursor von vielleicht 10 x 10 Pixel ändert trotzdem an den Treiber 320 x 240 Pixel gesendet werden (also die erwähnten 76.800 SetPixel() Aufrufe). Nötig wären nur 2 x 10 x 10 Aufrufe. Und in Refresh() darf man dann noch einen zweiten Buffer anlegen und in einer doppelten Schleife diese 76.800 Pixel mit den letzten 76.800 Pixeln vergleichen um den geänderten 200 Pixel auf die Schliche zu kommen :rolleyes: . Ist wohl bei den heutigen Prozessorgeschwindigkeiten und Speichergrößen keine große Sache mehr, aber irgendwie find ich das nicht optimal. Wie gesagt: nur ein Denkanstoß...


    Gruß
    superelchi

    Bin gerade dabei den Treiber zu optimieren. Dabei sind mir ein paar Dinge aufgefallen:


    Wie Keine_Ahnung ja schon sagte, ist der Display-Refresh nicht gerade der schnellste. Daran kann mann wohl nichts ändern. Ich versuche jetzt nur die Daten zu übertragen, die sich seit dem letzten Refresh() Aufruf geändert haben. Dazu baue ich mir in SetPixel() ein Dirty-Rectangle - also kleinste/größte Koordinate seit dem letzten Refresh() merken. Das klappt aber nicht, da auch bei der Änderung nur eines kleinen Bereichs immer der komplette Bildschirminhalt neu aufgebaut wird, d.h die SetPixel() Routine wird nach einer Änderung immer (width * height) Mal aufgerufen. Das sind bei dem Pearl-Display immerhin 320 x 240 = 76.800 Aufrufe. Okay, ich werde also das Ganze über einen doppelten Bildschirmbuffer lösen müssen, für den in in Refresh() einen Vergleich Alt <-> Neu gemacht und daraus das Dirty-Rectangle berechnet wird. Fände es allerdings im Sinne von verbratener Prozessorzeit und Resourcenverbrauch sinnvoller, nur geänderte Bereiche mit SetPixel() neu zu setzen. Nur so als Denkanstoß...


    In der ersten Version des Treibers habe ich das Setzen der Displayhelligkeit über SetBrightness() nicht implementiert, da es dabei hin und wieder zu Abstürzen des Displays kam. Hab das mal etwas genauer untersucht und rausgefunden, dass hier anscheinend zwei Threads gleichzeitig was von dem Treiber wollen. Während ein Thread Refresh() aufruft, versucht ein anderer gleichzeitig SetBrightness() aufzurufen. Da beide Routinen dann gleichzeitig versuchen mit dem Display über USB zu kommunizieren (und die libpdf aus dem Hack nicht threadsicher ist :wand ) machts PENG! Hab ich über Mutex gelöst. Wollte nur drauf hinweisen - vielleicht sollte man das irgendwo erwähnen, dass ein Graphlcd-Treiber threadsicher sein muss.


    Gruß
    superelchi

    Bei der kompletten Änderung (Normalansich->Menü) ist das mit dem seitlichen reinschieben garnicht so schlimm. Sieht wirklich so aus wie nen gewollter Effekt.

    Du hast die Portrait-Firmware drauf? Dann schiebt er standardmäßig von rechts nach links rein. Wenn Du es gerne von links nach rechts hättest kannst Du den Config-Parameter "UpsideDown=yes" setzen (dann empfiehlt es sich allerdings das Display um 180° zu drehen :D ).
    Wenn Du die Landscape-Firmware draufmachst, schiebt es standardmäßig von oben nach unten.


    Bekommt man die übergangslos zusammen (wenn man das Gehäuse abnimmt)?

    Nein, geht wohl nicht. Soweit ich mich erinnere, ist die Platine ist etwas größer als das Display. Aber hey - wir sind im Skin-Thread! Vielleicht macht ja jemand ein Skin, dass die Infos sinnvoll auf die einzelnen Display verteilt?


    Wobei man auch einfach mehere graphlcd Instanzen laufen lassen kann um auf meheren Displays unterschiedliche Infos anzeigen zu lassen.

    ..oder so. Kann man die auch über das VDR-Menü steuern?


    Gruß
    superelchi

    Was die Geschwindigkeit angeht: bin gerade dabei das zu optimieren. Momentan werden bei Teil-Refreshs noch unnötig viele Daten an das Display übertragen. Hilft natürlich nicht wenn der komplette Displayinhalt sich ändert. Aber immerhin...
    Kommt auch noch ein bisschen mehr an Features (Stichwort: mehrere Displays zu einem Großen zusammenschalten).


    Gruß
    superelchi