CUL Linux Treiber "simulieren"

412 views
Skip to first unread message

Survi

unread,
May 16, 2012, 10:17:31 AM5/16/12
to CUL fans
Hallo alle zusammen,

ich habe neben dem Studium gerade ein bisschen langeweile und will nun
mein FHEM/CUL auf ein RaspberryPI (ggf auch Beagle) "portieren". Dabei
kam mir die Idee z.B. einen Temperatursensor, Schalter oder so direkt
an die GPIOs anzuschließen und das entsprechende Protokoll/Endgerät zu
simulieren.

Ich kenn mich recht gut mit dem FS20 Protokoll und dem Hardwarekram
aus. Einziges Problem könnte der Treiber unter Linux werden. Ich habe
schonmal einen geschrieben (mit viel Fachliteratur Unterstützung), der
an einem GPIO Pin eine "1" oder eine "0" ausgibt. Mehr weiß ich leider
noch nicht über diese Thematik.

Daher wollte ich mal fragen, was FHEM braucht um einen CUL zu
initialisieren. Reicht das Zugriffsrecht (Lese/Schreibrecht) auf den
File aus oder muss da mehr vom CUL zurückkommen (Statusanfrage oder
so)? Die Befehle, die der "simulierte" CUL aussenden/empfangen muss,
kann ich ja in der Übersicht nachlesen.

Danke für die Hilfe

Rudolf Koenig

unread,
May 16, 2012, 2:53:17 PM5/16/12
to cul-...@googlegroups.com
> Daher wollte ich mal fragen, was FHEM braucht um einen CUL zu
> initialisieren. Reicht das Zugriffsrecht (Lese/Schreibrecht) auf den
> File aus oder muss da mehr vom CUL zur�ckkommen (Statusanfrage oder
> so)?

00_CUL_HM.pm fragt nach der Version (V), und wertet die Rueckgabe aus
(muss V <version> sein).

Ich wuerde aber vorschlagen kein CUL zu simulieren, sondern ein eigenes
Fhem-Modul fuer die GPIO zu schreiben, und daraus (aehnlich wie CUL und FHZ)
Dispatch() aufrufen.

Survi

unread,
May 18, 2012, 4:59:06 PM5/18/12
to CUL fans
Danke für die schnelle Antwort! Wenn ich den Initialisierungsvorgang
richtig verstanden habe, löst FHEM nach OPEN- den WRITE-Sytemcall auf
und schreibt dann nur ein "V" in den Treiber. Dann wartet es auf eine
Antwort ala "V 1.30" oderso. Sind das alles blockierende Aufrufe? kann
ich diese also in Queues stecken und wieder aufwecken?


> Ich wuerde aber vorschlagen kein CUL zu simulieren, sondern ein eigenes
> Fhem-Modul fuer die GPIO zu schreiben, und daraus (aehnlich wie CUL und FHZ)
> Dispatch() aufrufen.

Das wäre sicherlich eine schönere Lösung, allerdings bin ich beim
Programmieren eher eine Niete und kenne mich auch nur mit C aus. Ich
versuche immer möglichst viel auf uController runterzubrechen (wie
hier 2-Drahtkommunikation mit RaspberryPI, relais usw. werden vom uC
gesteuert). Ich habe noch nie mit Perl gearbeitet und schätze die
Einarbeitungszeit in den Aufbau von FHEM auch für erheblich länger
ein.

Auf jeden Fall nochmal vielen Dank für die Hilfe

Survi

unread,
May 18, 2012, 5:00:00 PM5/18/12
to CUL fans
Danke für die schnelle Antwort! Wenn ich den Initialisierungsvorgang
richtig verstanden habe, löst FHEM nach OPEN- den WRITE-Sytemcall auf
und schreibt dann nur ein "V" in den Treiber. Dann wartet es auf eine
Antwort ala "V 1.30 CUL868" oderso. Sind das alles blockierende

Survi

unread,
May 20, 2012, 8:29:10 AM5/20/12
to cul-...@googlegroups.com
Letzter Eintrag leider doppelt... Da habe ich wohl einmal zu viel gedrückt, als die Session abgelaufen war.

Ich habe mich jetzt einmal etwas länger mit der 00_CUL.pm und der DevIO.pm beschäftigt um den Open, Read und Write Prozess zu verstehen - Perl sieht doch sehr komisch aus, wenn man aus C kommt...

In der Funktion DevIo_OpenDev() erscheint der Openbefehl open($po, "+<$dev"). "+<" ist soweit ich gefunden haben also ein READ/WRITE Befehl, da kein O_NONBLOCK Flag gesetzt ist, müsste der zugriff blockierend sein.
In CUL_DoInit() ist auch die Abfrage nach der Version ersichtlich:
    CUL_SimpleWrite($hash, "V");
    ($err, $ver) = CUL_ReadAnswer($hash, "Version", 0, undef);


Leider sehe ich in meinem Treiber das "V" noch nicht, werde jetzt also mal die FHEM Logs auswerten (an welchen man sich auch ganz gut durch den Quellcode hangeln kann).

Survi

unread,
May 20, 2012, 9:17:06 AM5/20/12
to cul-...@googlegroups.com
Nachtrag:
Erwartungsgemäß sehe ich einen Fehler in den Logs: "Inappropriate ioctl for device". Im Quelltext finde ich jedoch keinmal den Aufruf ioctl() <- wenn es in Perl nicht noch eine andere Aufrufmöglichkeit gibt. Was erwartet FHEM hier? FHEM austicksen mit einem einfachen "return 0" funktioniert nicht.

Danke

Survi

unread,
May 20, 2012, 6:29:00 PM5/20/12
to cul-...@googlegroups.com
Und noch ein Nachtrag:

Auszug aus IODEV:

elsif($baudrate && lc($baudrate) eq "directio") {   # Without Device::SerialPort

    if(!open($po, "+<$dev")) {
      return undef if($reopen);
      Log(3, "Can't open $dev: $!");
      $readyfnlist{"$name.$dev"} = $hash;
      $hash->{STATE} = "disconnected";
      return "";
    }

    $hash->{DIODev} = $po;

    if( $^O =~ /Win/ ) {
      $readyfnlist{"$name.$dev"} = $hash;
    } else {
      $hash->{FD} = fileno($po);
      delete($readyfnlist{"$name.$dev"});
      $selectlist{"$name.$dev"} = $hash;
    }


  } else {                              # USB/Serial device


    if ($^O=~/Win/) {
     require Win32::SerialPort;
     $po = new Win32::SerialPort ($dev);
    } else  {
     require Device::SerialPort;
     $po = new Device::SerialPort ($dev);
    }

    if(!$po) {
      return undef if($reopen);
      Log(3, "Can't open $dev: $!");
      $readyfnlist{"$name.$dev"} = $hash;
      $hash->{STATE} = "disconnected";
      return "";
    }


Es ist egal, welche Verzweigung ich wähle (mit "directio"), ich erhalte immer die Fehlermeldung:
"Can't open /dev/rf_fs20: Inappropriate ioctl for device"

Ich weiß nicht, woher die Rückmeldung "
ENOTTY" kommt. Ich habe im Internet gelesen, dass Perl bei Open() (macht new Device::Serialport /dev/XXXX das gleiche?) automatisch auf TTY Device prüft, daher ioctl() automatisch aufgerufen wird. Diesen Ansatz werde ich erstmal weiter verfolgen, jedoch habe ich bis jetzt keine infos, was ioctl im Treiber machen soll.

Rudolf Koenig

unread,
May 21, 2012, 2:11:57 AM5/21/12
to cul-...@googlegroups.com
> Ich wei� nicht, woher die R�ckmeldung "ENOTTY" kommt.

Dann starte mal perl mit strace, damit Du die systemcalls siehst.


> dass Perl bei Open() (macht new Device::Serialport /dev/XXXX das
> gleiche?) automatisch auf TTY Device pr�ft, daher ioctl() automatisch
> aufgerufen wird.

Das habe ich auch bei anderen Programmen gesehen, wenn diese wissen wollen, ob
man seek verwenden kann.

Survi

unread,
May 21, 2012, 12:56:07 PM5/21/12
to cul-...@googlegroups.com
Ich hab jetzt mal ein einfaches Perl Programm geschrieben um das mit strace aufzurufen (FHEM liefert einfahc viel zu viele Rückgabewerte...). Kernelement lautet:

if(open(file, "+</dev/sim_cul")){
print file $text1;
}

Es wird auch ordnungsgemäß der text1 in den Driver geschrieben, also ist die IF Abfrage positiv. Die Systemcalls sehen so aus:

open("/dev/sim_cul", O_RDWR|O_LARGEFILE) = 3
ioctl(3, SNDCTL_TMR_TIMEBASE or TCGETS, 0xbfead4c8) = -1 ENOTTY (Inappropriate ioctl for device)
_llseek(3, 0, [0], SEEK_CUR)            = 0
fstat64(3, {st_mode=S_IFCHR|0666, st_rdev=makedev(251, 0), ...}) = 0
fcntl64(3, F_SETFD, FD_CLOEXEC)         = 0
write (...)


Man sieht also, dass ioctl wirklich aufgerufen wird und den gleichen Fehler auswirft. Jedoch übt sich dieser in keinsterweise aus. In FHEM wird ja scheinbar in dem Abschnitt


    if(!open($po, "+<$dev")) {
      return undef if($reopen);
      Log(3, "Can't open $dev: $!");
      $readyfnlist{"$name.$dev"} = $hash;
      $hash->{STATE} = "disconnected";
      return "";
    }

eine negative Rückmeldung gegeben. Ich muss wohl überprüfen, ob noch irgendwo anders der Fehler Log(3, "Can't open $dev: $!"); in Log geschrieben wird.

Survi

unread,
May 21, 2012, 1:09:15 PM5/21/12
to cul-...@googlegroups.com
 Ich muss wohl überprüfen, ob noch irgendwo anders der Fehler Log(3, "Can't open $dev: $!"); in Log geschrieben wird.


Der Fehler muss in der IF Abfrage sein, sonst müsste ich im log ein "device opened" sehen...

Willi

unread,
May 22, 2012, 1:09:37 AM5/22/12
to cul-...@googlegroups.com
Hallo Survi,

was hälst Du von der Alternative statt eines Devices ein TCP-Netzwerkgerät über Sockets zu simulieren? Auf diese Weise ersparst Du Dir evtl. betriebsystemspezifische Probleme mit Devices.

Dein Modul ist dann auch universeller über Netzwerk nutzbar und kann auch ohne root laufen..

Ich nutze bei meinem Code (TRX, RFXCOM) meist TCP für die Tests (über die Programme netcat, nc) zur Simulation. Damit ich die Initialisierung nicht nachstellen muss, haben meine Module eine "noinit"-Option.

Survi

unread,
May 24, 2012, 8:44:45 AM5/24/12
to cul-...@googlegroups.com


Wäre sicherlich auch eine Möglichkeit, jetzt verfolg ich aber erstmal den Ansatz mit dem Treiber (ab einem bestimmten Punkt will man es einfach durchziehen^^)

Interessanter Weise kam der Fehler nach einer erneuten Installation nicht mehr auf. Jetzt pass ich den Treiber noch weiter an. Ich hab allerdings öfter das Problem, dass ich mit "define XXX CUL XXXX" keinen neuen CUL anlegen kann. In den meisten Fällen hab ich vorher einen gelöscht um Fehler in dem Init Teil zu sehen. Es kommt auch keine Fehlermeldung oder so, es wird nur kein neues Gerät angelegt. Gibts dafür eine Erklärung?

Survi

unread,
May 24, 2012, 12:32:34 PM5/24/12
to cul-...@googlegroups.com
Mein Treiber wird jetzt erfolgreich initialisiert - war ohne diesen ioctl Fehler recht einfach, besonders aufgrund der log möglichkeiten.

die letzte Abfrage kommt mir zwar komsich vor (warum muss in der übergabe 2* \n stehen?) aber egal.

Danke für die Hilfe

Survi

unread,
Jun 11, 2012, 10:22:15 AM6/11/12
to cul-...@googlegroups.com
Ich habe noch ein bisschen weiter an meinem Treiber geschrieben und musste feststellen, dass ich noch nicht alle Teile des FHEM Programm Codes verstehe. Gibt es eine Übersicht über dei gesamten Datenstruktur eines CUL Devices? Momentan habe ich ein Problem in der 00_CUL.pm:

Aus CUL_ReadAnswer()

$buf = $hash ->{USBDev}->read(999);
return("Timeout ....") if(length(%buf) == 0);

Was passiert in dieser Zeile? Warum kommt es hier zu einem Timeout? Diese Werte in USBDev werden doch nur von FHEM beeinflusst und nicht vom CUL oder? Ruft "->read" oder "->write" eine Funktion auf?
Ich komme mit den ganzen Werten nicht zurecht, die in hash->XXX festgehalten sind.....

Rudolf Koenig

unread,
Jun 11, 2012, 12:25:41 PM6/11/12
to cul-...@googlegroups.com
> Warum kommt es hier zu einem Timeout?

Weil das Geraet / Treiber keine Daten liefert..?


> Ruft "->read" oder "->write" eine Funktion auf?

Sicher doch, hoffentlich die syscalls read und write. Versuchs mal mit
strace perl fhem.pl fhem.cfg
strace redet eher Deine Sprache

MARC JOHNEN

unread,
Jun 11, 2012, 2:31:18 PM6/11/12
to cul-...@googlegroups.com

Survi <thomas.n...@googlemail.com> schrieb:

>--
>To unsubscribe from this group, send email to
>cul-fans+u...@googlegroups.com

Survi

unread,
Jun 11, 2012, 5:32:46 PM6/11/12
to cul-...@googlegroups.com
Den letzten Eintrag überspringe ich mal.

Ich hatte mir schon gedacht, dass ein systemcall erfolgt - über das read(999) erfolgt doch irgendwo (wo genau?) anders ein Funktionsaufruf oder?. Soweit ich weiß, versteht der CUL nur Anweisungen, die mit A a B C c D d E e F f G I i M l O P q R s T t u V W w X  beginnen. Wo wird den der Parameter "999" aufgelöst?

Kommt irgendwann dann wieder ein DevIO Aufruf?

Auf jeden Fall schonmal danke für die schnelle Antwort!

Rudolf Koenig

unread,
Jun 12, 2012, 1:40:15 AM6/12/12
to cul-...@googlegroups.com
> Wo wird den der Parameter "999" aufgel�st?

Irgendwo in Device::SerialPort oder Win32::SerialPort. Und bedeutet laut
"perldoc Device::SerialPort" anzahl der maximal zu lesenden Bytes.

Survi

unread,
Jun 22, 2012, 6:02:21 AM6/22/12
to cul-...@googlegroups.com
Treiber läuft jetzt recht gut, er wird voll initialisiert und ich kann Daten ausgeben. Allerdings hab ich auch inzwischen zwei Perl Bücher hier liegen und komm mit dem CU-Modul ganz gut zu recht. Vielleicht werd ich doch noch ein eigenes schreiben...

Daten einlesen funktioniert leider nicht, alles was ich in den Treiber schreibe kommt nicht in FHEM an (zumindest nichts aus der Global Loop), die CUL_Answers sind kein Problem("V", "T01" usw. wird beantwortet)

Der CUL wird scheinbar nicht passiv ausgelesen, es gibt keinen InternalTimer in CUL_Define($$).

Mechanismus fuer aktive Readings: TODO: Mechanismus mit ParseFn, GetFn, Match usw. beschreiben (wie in fhem 4.x)!

Verdammt ;-)

Dennoch vielen Dank für die Hilfe -> bin mit dem Ergebinis sehr zufrieden. Steuere gerade 6 indirekte Beleuchtungen hinter meinem Fernsehr (raum voll beleuchtet -> kino flair -> komplette Dunkelheit) - Danke!

Rudolf Koenig

unread,
Jun 22, 2012, 6:16:42 AM6/22/12
to cul-...@googlegroups.com
> Der CUL wird scheinbar nicht passiv ausgelesen, es gibt keinen
> InternalTimer in CUL_Define($$).

Unter Linux wird nicht gepollt, sondern via select auf Daten gewartet. Unter
Windows pollt fhem alle USB Geraete (da Windows select nur fuer sockets
anbietet), wenn Du also Deinen Treiber schnell noch unter Windows
implementierst, dann musst Du fhem nicht aendern :)

Survi

unread,
Jun 22, 2012, 6:56:03 AM6/22/12
to cul-...@googlegroups.com
Ich bin mir nicht sicher, ob ich select() verstanden habe... Im Grunde genommen prüft select doch nur, ob an dem FD Daten anliegen oder nicht (ohne das Device zu blockieren und mit Timeout). Somit müsste dieser auch die Daten "finden", die ich in meinen Treiber schreibe. Ich sag dann ja zum Beispiel "F12345600\n\n" (z.b. fernsehr wurde ausgeschaltet) und gebe dem Treiber bekannt, dass 11 Byte zum schreiben bereit sind.

select() wird glaub ich auch in CUL_ReadAnswer verwendet und funktioniert dabei auch. Ich prüf mal meine write funktion....

Rudolf Koenig

unread,
Jun 22, 2012, 7:19:09 AM6/22/12
to cul-...@googlegroups.com
> Ich sag dann ja zum Beispiel "F12345600\n\n" (z.b. fernsehr wurde
> ausgeschaltet) und gebe dem Treiber bekannt, dass 11 Byte zum schreiben
> bereit sind.

Aus meiner grauer Vorzeit als Kernel-Programmierer meine ich noch zu wissen,
dass der Treiber select aktiv unterstuetzen muss, da select eine Kernel und
nicht "nur" Bibliotheksfunktion ist. Evtl. wird im Linux Kernel select unter
dem SYSV Namen poll implementiert.

Survi

unread,
Jun 22, 2012, 7:34:21 PM6/22/12
to cul-...@googlegroups.com

Aus meiner grauer Vorzeit als Kernel-Programmierer meine ich noch zu wissen,
dass der Treiber select aktiv unterstuetzen muss, da select eine Kernel und
nicht "nur" Bibliotheksfunktion ist. Evtl. wird im Linux Kernel select unter
dem SYSV Namen poll implementiert.


 Ja absolut richtig. Gerade nochmal nachgeschlagen: im Treiber muss eine Funktion driver_poll exisiteren, die für poll() und select() benötigt wird. Es funktioniert jetzt auch alles soweit, leider schneidet FHEM die letzten beiden elemente ab.

Ich muss nur noch herausfinden, was der Ausdruck if("$dmsg =~ m/^[AFTKEHRS]([A-F0-9][A-F0-9])+$/") abfragt. dmsg ist F12345600, da die IF Abfrage wahr ist, wird dann zwei Elemente abgeschnitten und FHEM versteht die Nachricht "F123456" nicht. Der Ausdruck heißt doch ...beginnt mit AFTK... dann hexkette (bis 9?) +$/(???) - ich versteh  die abfrage nicht, normalerweise überträgt der CUL das extended byte doch nur wenns benötigt wird... naja ein bisschen weiter probieren

Rudolf Koenig

unread,
Jun 23, 2012, 6:31:49 AM6/23/12
to cul-...@googlegroups.com
> Es funktioniert jetzt auch alles soweit, leider schneidet FHEM die letzten
> beiden elemente ab.

Klar, da kommt normalerweise das RSSI (Empfangsstaerke).
Reply all
Reply to author
Forward
0 new messages