* Was machen wir mit Properties, die den Datentyp `Structure' haben, z.B. MagnInfo? -> Ok! Ist implementiert. * Gibt's eigentlich nur asynchrones *Lesen* oder z.B. auch ein asynchrones *Call*? Ich denke ja! Wir schalten doch jetzt schon Magnete entlang einer Beamline asynchron ein, weil das synchrone Einschalten zu lange dauern würde. Die gleiche Frage steht für "konnektierte Aufträge". Ist es nicht vorstellbar, dass man vom Operating aus sagen kann, dass dem DC-Magneten XX1MU2 alle 200ms der (DPR-) Sollwert geschickt werden soll? -> Ok! Geht für alle nicht synchronen Aufträge. * Wählen wir für Callbacks die Implementierung mit "oneway", dann [1] beachten! Bei Callbacks ebenso "TRANSIENT" beachten, siehe [2]. -> Ok, aber TRANSIENT fehlt noch. * UsrArray::addUsr() wirft eine Exception, wenn das Array bereits voll ist, und wird *im Konstruktor* von MxUsrs benutzt. Wie geht das? Wo endet die Exception, also wer fängt sie? -> Ok, wg. Benutzung von " vector". * UsrArray::getUsrs(...) sucht eine passende Usr mit einer ziemlich schlechten Suchmethode, indem nämlich einfach das Array von Anfang an durchgeklappert wird. Kann man da was besseres, schnelleres erfinden? Möglicherweise mit "map" implementieren. -> Ok! Mit "map" aus der STL implementiert. * Die Kennung konnektierter Aufträge mit IDs ist nicht mehr uptodate. Die Methode connect() sollte eine Referenz auf die "Konnektierung" (was immer das genau ist) zurück liefern, die von der Methode disconnect() benutzt werden kann. -> Ok, ID und Objektreferenz mit "set" (STL) implementiert. * Geräte müssen die virtuellen (s.o.) Methoden setOnline() und setOffline() zur Verfügung stellen. setOnline() muss die Attribute MxDevice::_devDataP und VmeDevice::_ecNum versorgen. Wer weiß genau, wo die Daten des Gerätes im DPR anfangen? Was kann MOPS als Parameter an setOnline() übergeben? Die Methoden mit mutex abichern. -> Ok! * Wie setze ich das Attribut _devConst der Klasse MxDevice? Die Gerätekonstanten _devConst müssen (neu) gefüllt werden, wenn neue Konstanten von oben (Operating-Ebene) geschickt werden. Wenn _devConst neu gefüllt wird, müssen auch die Konstanten im DPR neu geschrieben werden! Geräte müssen eine virtuelle Methode setDevConst() zur Verfügung stellen zum Setzen/Updaten der Geräte- konstanten. "Virtuell", weil MOPS VmeDevice::setDevConst() aufruft (er soll nix von MxDevice wissen), aber aktuell natürlich MxDevice::setDevConst() aufgerufen werden muss. Welcher allgemeine Datentyp wird benutzt, um die Konstanten auszutauschen? Etwa ein Array of Structures ähnlich dem in narrowifc.idl deklarierten? union DevConstElement switch (DataType) { ... case DATA_SLONG: long sl; ... } typedef vector<DevConstElement> DevConstArray; virtual void VmeDevice::setdevConst(DevConstArray& dca); virtual void MxDevice::setdevConst(DevConstArray& dca); Kann/soll man direkt den IDL-Typ `StructArray' benutzen? -> Ok! * Kann der MOPS Geräte (z.B. PlaDevice) instanziieren, *ohne* dass er konkret was von dem Device weiß, also ohne dass er pla-device.hh includieren muss? Vielleicht geht's so: Jedes Gerätemodell steckt in einer eigenen Shared Library. Jedes Gerätemodell hat eine Methode, die etwa `instantiate()' heißen könnte. Diese instanziiert ein Gerät (new PlaDevice) und liefert dem MOPS eine Referenz (oder einen Pointer) auf das Objekt zurück. Die Referenz kann vom Typ `VmeDevice' oder `AccDevice' oder einfach `CORBA::Object[_var]' sein. (Dabei ist `CORBA::Object_var' wohl besser als `CORBA::Object', weil der `Smart'-Pointer Eigentümer des Objekts wird und es damit auch zur passenden Zeit wieder löschen kann.) -> Ok! * Nach einem disconnect() kommt in der Regel trotzdem noch *eine* konnektierte Antwort. Das liegt an der Implementierung in vmedevice.cc. Will man diese letzte Antwort vermeiden, muss nach dem Warten nochmal explizit geguckt werden, ob die USR mittlerweile disconnected wurde. -> Ok! In ConnectThread::run() implementiert. * Absturz (Segmentation fault) des Servers, wenn das konnektierte FIELDA einen Parameter bekommt, der eigentlich für CALC gedacht war. Mit cl2.cc reproduzierbar. Woran liegt's? Stürzt der Server eigentlich auch bei einem (a-)synchronen Auftrag ab? Weder noch, Absturz also *nur* nach einem konnektierten Auftrag! -> Ok! War das Dereferenzieren eines NULL-Pointers in der FieldA-USR, weil ich einen primStat nicht getestet hatte. Warum das aber nur bei einem konnektierten Auftrag passiert ist, fragt mich bitte keiner! * Für asynchrone und konnektierte Aufträge müssen die von einer USR geworfenen Ausnahmen gefangen und als AccDevRetStatus an den Client (-Callback) zurück geliefert werden. -> Ok! Ist kein Callback angegeben (ohne quit), muss die Ausnahme auf der Server-Seite ausgegeben werden (cerr). -> Ok! Zumindest als Kommentar in vmedevice.cc implementiert. * Was machen wir mit den Standard-USRs? In Gerätemodell-USRs includiren? Dazu linken? Vererben? Oder was? -> Vorläufig ok! Default- und Therapie-USRs werden weiterhin einfach includiert. Für andere Implementierungen (z.B. erben) muss man noch gut nachdenken, weil die includierten USRs gerätemodell-spezifische Informationen benötigen, die sie jetzt einfach haben, weil diese vor dem Include definiert werden. In etwa so, z.B. in mx-usrs.cc: #define MEDIMODE_TIMEOUT 15 #include "therapy-usrs.cc" * Namespaces auch für VmeDevice und AccDevice erfinden? Ja! -> Ok, im Namespace DeviceAccess * Wie machen wir die Incode Documentation? Mit Doxygen? Wieder einen (oder mehrere) Rahmen für Klassen, USRs, etc. entwickeln? -> Ok, mit Doxygen. Einen Rahmen gibt's (noch) nicht. * Allgemeines, CORBA-unabhängiges AccData implementieren. Nur damit gibt es auch die Konvertierung beim Lesen von AccData (also wenn Daten an ein Gerät geschickt werden)! Zur Zeit ist *keine* Datenkonvertierung eingebaut. -> Ok! * Überall den Server bzw. den nMOPS von Klaus benutzen. Dieser kann u.a. die Datenbank (Geräte- und Konstanten-Tabelle) via File einlesen. -> Ok! * Wie behandeln wir die Geräte-Software-Shared-Objects, also z.B. "mx.so" oder "pla.so"? Diese werden ja zur Laufzeit "dazugelinkt". Liegen sie für jeden GuP allgemein zugänglich, dann hat jeder GuP automatisch die neueste GSW. Das ist schön, man mag's aber manchmal gerade so *nicht* haben, weil man auf einem GuP noch mit älterer Software fahren möchte! Was machen wir dann? Anders linken? Oder benutzen wir gar keine Shared Objects? Oder was? Shared Objects getrennt für jeden GuP macht jedenfalls keinen Sinn. -> Ok, auf dem Root-Directory des PPC gibt es z.B. einen Link "mx.so", der z.B. auf "/usr/local/lib/mx.so.9.2" zeigt. Das ist ein Link, der z.B. auf "/usr/local/lib/mx.so.9.2.7" zeigt. Das ist die Shared Library für MX. Änderungen von 9.2.7 auf 9.2.8 werden also "automatisch" von allen PPCs berücksichtigt, Änderungen von 9.2 auf 9.3 müssen für jeden PPC einzeln "released" werden, indem der Link mx.so auf dem Root-Directory umgesetzt wird. * Manchmal werden gewisse Deklarationen für ein Gerätemodell auf Server- *und* Clientseite gebraucht, z.B. MagnInfoType bei MX. Auf der Clientseite soll man deshalb aber *nicht* mx-usrs.hh oder mx-device.hh includieren müssen, da das einen Rattenschwanz von weiteren Includes nach sich zieht. Erfinden wir sowas wie ein mx-global.hh? Oder muss man MagnInfoType auf der Clientseite einfach nochmal deklarieren? So wurde es wohl bisher gemacht. Auch sollte der (mehr oder weniger Standalone-) Server (MOPS) weitgehend von gerätespezifischen Includes (z.B. mx-dev-def.h) verschont bleiben. Das bedeutet,dass die Include-Files entflochten werden müssen! Im Moment habe ich für die MX-Properties MAGNINFO und CALC die Datei mx-structtypes.hh erfunden. Es ist wohl sinnig, für strukturierte Datentypen auch auf der Server-Seite ein (dieses) Include zu haben. Die Grenzen dieser Lösung zeigt nun therapy-structtypes.hh auf. Jedes enum-Element muss einen *eindeutigen* Namen haben. So kann man z.B. "iFocus" nicht in 2 Aufzählungen als Namen nehmen. Und einen Typ wie z.B. typedef struct RCheckSetSndType { ULong OperMode; ULong MstCompl; ULong SlvCompl; ULong VfyCompl; ULong CntBadSets; DEFIType BadSets[CNTBADSETS_MAX]; } RCheckSetSndType; (der nur aus ULong-Elementen besteht) in eine Aufzählung zu überführen, ist ziemlich unschön. Wollen wir also die "typedef struct ..." auch alle beibehalten? Sehen wir da Probleme mit Alignment usw.? -> Ok! - gm-structtypes.hh wird implementiert und nach $incvme kopiert. - Eindeutige Benennung von Aufzählungselementen wird durch property-ähnliche Zusätze erreicht (siehe md-structtypes.hh). - Arrays bekommen nur _einen_ Index auf den Array-Anfang. - Alignment-Probleme gibt es keine, da man auf AccData-Elemente nur einzeln zugreifen kann. * UsrSet::addUsr(): Fehlerbehandlung beim Versuch, eine Property mehrfach anzumelden. -> Ok, es gibt eine Exception. * Was machen wir generell mit Fehlern, die nicht an einen Client gemeldet werden können? Vorschlag wäre, sie in ein Logfile zu schreiben. Diese Möglichkeit hätten wir jetzt mit den neuen PPC-GuPs (via NFS). -> Ok, Logfile. * Man muss beachten, *wohin* Geräte-Software eine Exception wirft. - Wenn eine USR eine Exception wirft, dann wird sie in Richtung Anwendung (Operating-Programm) geworfen. Dort kann sie ausgewertet werden. - Geräte (Klassen VmeDevice, MxDevice) haben aber u.a. auch Methoden, die *nicht* von einem Operating-Programm, sondern von DevMan aufgerufen werden, z.B. online() oder getDevConstants(). Eine darin geworfenen Exception landet also in DevMan. Was macht der damit? Wollen wir ein GuP-spezifisches Logfile erfinden, in das solche Exceptions (und andere Probleme) geloggt werden? (Siehe dazu auch einen Punkt weiter oben.) Je nachdem, wer wirft und wohin geworfen wird, muss man gucken, ob man eine CORBA-abhängige AccDevExc wirft oder eine unabhängige AccDevException. - Wirft man Richtung DevMan, dann sollte (muss?) es eine AccDevException sein, also die CORBA-unabhängige. - USRs werfen auch AccDevExceptions, die von VmeDevice in eine entsprechende AccDevExc konvertiert und mit Hilfe von CORBA weitergeworfen werden. - Im Sinne der Trennung von Anwendung und Transport sollte MxDevice eigentlich auch nur AccDevExceptions werfen. MxDevice ist aber ein Kind von VmeDevice. Und ich weiß (im Moment noch) nicht, wie man da VmeDevice noch konvertieren lassen könnte, wenn die Exception Richtung Anwendung fliegt. Im Moment haben wir das Problem (noch) nicht, da die Exceptions aus MxDevice alle Richtung DevMan geworfen werden. -> Ok! - USRs und DevMan schreiben in ein GuP-spezifisches Logfile. - Nur CORBA-Module und (zum Teil) die Interfaces zwischen CORBA und den CORBA-unabhängigen Teilen werfen AccDevExc. Alle anderen Module werfen AccDevException. -> Ok! - Beim Starten des DevMan kann es zu Fehlermeldungen wie z.B. Couldn't load so file ec.so (ec.so: cannot open shared object file: No such file or directory) kommen. Die werden im Moment noch am Bildschirm ausgegeben, müssen aber perspektivisch auf das Logfile umgelenkt werden. -> Ok! Meldungen umgelenkt! * Devman sollte verhindern, dass er mehr als einmal läuft. Das geht nämlich wegen der Resource VME nicht und macht zudem Probleme mit den Objekt- Referenzen, die dem Nameservice bekannt gegeben werden. Ich habe nach einem Lock-Mechanismus Ausschau gehalten. So richtig was Schönes gibt es anscheinend unter Linux nicht. Am praktikabelsten erscheint mir die Methode der Dateisperrung, wie sie in "Linux Programmierung" ab Seite 258 beschrieben ist. Das würde für den Devman etwa so aussehen: { if (kreiere(Lockdatei) != ok) { log error exit } ... } exithandler() { lösche(Lockdatei) ... } Eine Lockdatei könnte etwa devman.lock heißen und müsste auf einem rechnerspezifischen Directory liegen. Wo könnte das sein? -> Ok! Sieht zwar im Detail ganz anders aus, aber funktioniert. Lockdatei heisst: /var/lock/acc/devman * Callback bremst konnektierte Aufträge aus. So, wie die run-Methode des ConnectThreads im Moment implementiert ist, wird die Zeit, die die Callback-Methode der Anwendung braucht, zur sleep()-Zeit _addiert_! Das kommt daher, weil die Callback-Methoden _synchrone_ Methoden sind. Hat der Anwender eine periodische Konnektierung aufgesetzt, die z.B. alle 10s antworten soll, und sein Callback braucht 5s, dann gibt es nur alle 15s eine Antwort, weil das "_client->readResponse(...)" in "ConnectThread::run(...)" erst nach 5s zurück kommt und dann noch 10s geschlafen wird. So kann man das nicht lassen. Peter hat aber eine gute Idee, wie man das beheben kann. Und die Realisierung hat noch einen zusätzlichen angenehmen Nebeneffekt. Der sleep()-Timer wird in einem eigenen Thread aufgesetzt, der ConnectThread ruft den Callback auf und macht anschließend ein join() mit dem sleep()-Thread. Solange der Callback weniger lange dauert als die sleep()-Zeit, bekommt der Anwender seine Antworten in der gewünschten Frequenz. Braucht der Callback länger als die sleep()-Zeit, dann bremst der Anwender den ConnectThread aus. Er bekommt seltener eine Antwort, weil zum join()-Zeitpunkt der sleep()- Thread schon längst abgelaufen ist. Die Periode entspricht dann der Laufzeit des Callbacks. Und das ist der angenehme Nebeneffekt: Es macht keinen Sinn, mehr bzw. öfter Antworten an den Anwender zu schicken als dieser verarbeiten kann. -> Ok! Ist nun so realisiert, dass die USR-Laufzeit von der Periode abgezogen wird. Das hat den gleichen Effekt wie oben beschrieben. Nur zwischen Aufsetzen des Auftrags und erstem Ablauf addieren sich die Zeiten. * Die Gruppierung der Doxygen-Doku für VmeDevice, Default- und Therapie-USRs, USR-Support neu machen oder aufheben. Nötig, weil die USRs in ein eigenes Projekt "usrs" gerutscht sind. -> Ok! * A long lasting problem with event connected commands should be solved: It is possible to connect to events in *all* virtual accelerators. But presently the call is executed for the virtual accelerator which is specified in the device access description, which is the same then for all execution of the event connected command. What is more naturally expected would be: - When the event is recognized in the virtual accelerator n, the call should be made for the virtual accelerator n, - when the event is recognized in the virtual accelerator m, the call should be made for the virtual accelerator m. Should in case of event connection the virtual accelerator of the event be used (that is, for connection to all events, the momentarily running virtual accelerator? Or should this behavior explicitly be requested? -> Ok! * Auf asl (x86) will <nop>DevMan "ec.so" laden. Das sollte er aber nicht wollen, da es hier keine SEs gibt. Fehlermeldungen im Logfile sind: Aug 3 09:08:47 asl710 DevMan[23020]: devman.cc::initSE:397: Couldn't load so file ec.so (ec.so: cannot open shared object file: No such file or directory) Aug 3 09:08:47 asl710 DevMan[23020]: devman.cc::initSE:444: terminated with exception: ec.so, Primary status = 202153792, Secondary status = 202153792 -> Ok! initSE wird nur noch auf der __powerpc__ -Plattform ausgeführt. * Ein Gerät wird _offline_ gemeldet, ist aber auf der SE gar nicht (mehr) vorhanden (_unknown_). =TR2QT21 XSR-E-DEV_OFFLINE, Gerät ist offline= War wohl mal online, auf der SE gab's aber mittlerweile einen INIT. Ist's nicht auf der SE bekannt, sollte es als unknown gemeldet werden. Oder anders: Es sollte immer der Zustand gemeldet werden, der von der SE gemeldet wird und den man im SE-Display sehen kann. -> Ok! * Der Devman legt _immer_ alle neun EC-Objekte an, auch wenn nicht alle Slots mit SEs bestückt sind. Schön wäre, wenn es nur für die vorhandenen SEs ein entsprechendes Objekt gäbe. -> Ok! das macht er jetzt nicht mehr, sondern nur noch SEs, die mindestens mapped (also als physischer Speicher vorhanden) sind * Beim Generieren des Devman sollte sowas wie ein devman-version.hh erzeugt werden, das in der Methode getVersionStrings() in dman-device.cc benutzt werden kann. Beachten: X86- und PPC-Devman haben unterschiedliche Versionsnummern! X86 hat 01.xx.yy und PPC hat 09.xx.yy. Das dman-usrs-version.hh für die Version der Devman-USRs muss auch generiert werden. Das ist zur Zeit noch handgemacht! -> Ok! ist in make.mk drin * ec-online-check verbessern, sodass in der Restart-Phase der SE kein Unsinn passiert (von devman aus). Dazu z.B. ecmDisplay.status != STAT_INIT prüfen -> Ok! hat sich anderweitig erledigt * Für DEVDESC - und wohl für andere Properties auch - muss man bedenken, dass sie auch von Userface aus gelesen werden können. So müssen Strings, etwa die Nomenklaturen, immer gleich lang (8 Zeichen) sein. Notfalls ist vor dem verschicken Blank-Padding notwendig! -> Ok, DEVDESC2 erfunden. * Brauchen wir eigentlich auch ein reldevman, wie wir unter V08 ein relmops hatten? Also auf /opt/acc/cpu einen Link setzen auf den gewünschten devman.so.ss.dd.pp, der auf /usr/local/lib liegt? Und was ist mit all den anderen "Nicht-Gerätemodell"-so-Files auf /usr/local/lib, wie z.B. vmeconfig.so.ss.dd.pp, accdata.so.ss.dd.pp usw.? Die müsste man doch auch cpu-spezifisch versionieren können. -> Ok, wird mit Release 8 erledigt. * Sollte man im DevMan statt fest verdrahteter Directories, wie z.B. /opt/acc/cpu, nicht besser auf Umgebungsvariablen zurückgreifen? Die kann man dann plattform-spezifisch setzen. Und man hätte den Vorteil, dass man nicht überall die gleiche Umgebung braucht. -> Ok, bleibt zunächst so.