TSCUL für CUL mit HM-Timestamp

Begonnen von noansi, 18 September 2016, 10:46:28

Vorheriges Thema - Nächstes Thema

noansi

Hallo Rudolf, hallo Martin,

hier https://forum.fhem.de/index.php/topic,24436.msg489979.html#msg489979 liegt die aktuelle CUL Timestamp Variante.
Diese kann fast neben den letzten standard Versionen in FHEM existieren, da die geänderten Module weitgehend eigenständig sind, also TSCUL, TSSTACKED etc. neben CUL, STACKABLE_CC etc. .


Eine neue Utility Datei "CUL_Util.pm" habe ich dazu kreiert, in der Hilfs-Funktionen zur Zusammenarbeit enthalten sind:

##############################################
# $Id: CUL_Util.pm 0003 2016-09-18 00:14:47Z noansi $
package main;

sub IsRealCUL($);
sub IsCULTYPE($);
sub IsTSCULTYPE($);
sub PrefixCULCommonClients($);
sub AppendCULCommonClients($);


########################
sub
IsRealCUL($)
{
  my ($t) = @_; # TYPE
  return (
              ($t eq "TSCUL")
           || ($t eq "CUL")
         );
}

########################
sub
IsCULTYPE($)
{
  my ($t) = @_; # TYPE
  return (
              ($t eq "TSCUL")
           || ($t eq "TSSTACKED")
           || ($t eq "CUL")
           || ($t eq "STACKABLE_CC")
         );
}

########################
sub
IsTSCULTYPE($)
{
  my ($t) = @_; # TYPE
  return (
              ($t eq "TSCUL")
           || ($t eq "TSSTACKED")
         );
}


########################
sub
PrefixCULCommonClients($)
{
  my ($Clients) = @_;
  $Clients = ':'.$Clients  if ($Clients !~ m/^:/);
  $Clients = "TSSTACKED:STACKABLE_CC".$Clients;
  return $Clients;
}

########################
sub
AppendCULCommonClients($)
{
  my ($Clients) = @_;
  $Clients .= ':' if ($Clients !~ m/:$/);
  $Clients .= "TSSTACKED:STACKABLE_CC";
  return $Clients;
}

1;



@Martin: In 10_CUL_HM.pm sind dafür folgende mit TSCUL markierte Änderungen erforderlich. Ich habe auch noch die nur einfache pair request Unterdrückung rein gebracht, da sie meiner Ansicht nach notwendig ist.

--- org/10_CUL_HM.pm Sun Sep 18 09:37:46 2016
+++ changed/10_CUL_HM.pm Sun Sep 18 09:38:10 2016
@@ -1,7 +1,7 @@
##############################################
##############################################
# CUL HomeMatic handler
-# $Id: 10_CUL_HM.pm 12138 2016-09-11 15:21:08Z martinp876 $
+# $Id: 10_CUL_HM.pm 12138a 2016-09-18 09:07:08Z martinp876/noansi $

package main;

@@ -131,6 +131,8 @@
sub CUL_HM_Initialize($) {
   my ($hash) = @_;

+  require "$attr{global}{modpath}/FHEM/CUL_Util.pm";  # ToDo TSCUL
+
   $hash->{Match}     = "^A....................";
   $hash->{DefFn}     = "CUL_HM_Define";
   $hash->{UndefFn}   = "CUL_HM_Undef";
@@ -155,6 +157,9 @@
                        ."msgRepeat "
                        ."hmProtocolEvents:0_off,1_dump,2_dumpFull,3_dumpTrigger "
                        ."aesKey:5,4,3,2,1,0  "
+#                       ."hmDstDly:slider,104,4,136 "     # Change noansi # TSCUL destination answer delay, for testing
+#                       ."sndThrRep:0,1 "                 # Change noansi # TSCUL force expectation of send through repeater, for testing
+#                       ."repBstAddDly:slider,0,4,600 "   # Change noansi # TSCUL additional first answer delay for burst devices using repeater to device, 512 is a good value for HM-LC-SW1-BA-PCB, for testing
                        ;
   $hash->{Attr}{chn} =  "repPeers "            # -- channel only attributes
                        ."peerIDs "
@@ -2875,6 +2880,7 @@
                              $devHlpr->{HM_CMDNR} < 250);# this is power on
   $devHlpr->{HM_CMDNR} = hex($mhp->{mNo});# sync msgNo
   my $repeat;
+  $devHlpr->{supp_Pair_Rep} = 0 if ($mhp->{mTp} ne "00"); # reset suppress flag as we got something different from device # Change noansi 
   if   ($mhp->{mTp} eq "02"){# Ack/Nack/aesReq ####################
     my $reply;
     my $success;
@@ -3038,9 +3044,12 @@
   }

   elsif($mhp->{mTp} eq "00"){######################################
-    if (InternalVal($mhp->{devN},"lastMsg","") =~ m/t:00/){# repeated
+    if ($devHlpr->{supp_Pair_Rep}){# repeated  # Change noansi
+      $devHlpr->{supp_Pair_Rep} = 0; # reset flag, suppress only once not to lockup if device answer is not received # Change noansi
       return "done";  # suppress handling of a repeated pair request
     }
+    $devHlpr->{supp_Pair_Rep} = 1;  # suppress next handling of a repeated pair request # Change noansi
+
     my $paired = 0; #internal flag
     CUL_HM_infoUpdtDevData($mhp->{devN}, $mhp->{devH},$mhp->{p})
                   if (!$modules{CUL_HM}{helper}{hmManualOper});
@@ -3097,7 +3106,7 @@
       $respRemoved = 1;#force command stack processing
     }

-    $devHlpr->{HM_CMDNR} += 20;  # force new setting. Send will take care of module 255
+    $devHlpr->{HM_CMDNR} += 0x27;  # force new setting. Send will take care of module 255
     $ret = "done";
   }
   elsif($mhp->{mTp} eq "10"){######################################
@@ -8473,7 +8482,7 @@
     next if (!$defs{$ioN});
     if (  $defs{$ioN}{TYPE} =~ m/^(HMLAN|HMUARTLGW)$/){;
     }
-    elsif(($defs{$ioN}{TYPE} eq "CUL")||($defs{$ioN}{TYPE} eq "STACKABLE_CC")){
+    elsif( IsCULTYPE($defs{$ioN}{TYPE}) ){  # ToDo TSCUL
       CommandAttr(undef, "$ioN rfmode HomeMatic")
             if (AttrVal($ioN,"rfmode","") ne "HomeMatic");
     }



@Rudolf: Hier die dazu nötigen Änderungen für 00_CUL.pm

--- old/00_CUL.pm Sun Aug 21 12:05:23 2016
+++ changed/00_CUL.pm Sun Sep 18 01:40:03 2016
@@ -1,5 +1,5 @@
##############################################
-# $Id: 00_CUL.pm 12027 2016-08-21 12:05:23Z rudolfkoenig $
+# $Id: 00_CUL.pm 12027 2016-08-21 12:05:23Z rudolfkoenig/noansi $
package main;

use strict;
@@ -45,14 +45,15 @@

my @ampllist = (24, 27, 30, 33, 36, 38, 40, 42); # rAmpl(dB)

-my $clientsSlowRF    = ":FS20:FHT.*:KS300:USF1000:BS:HMS: ".
+my $clientsSlowRF    = " :FS20:FHT.*:KS300:USF1000:BS:HMS: ".
                        ":CUL_EM:CUL_WS:CUL_FHTTK:CUL_HOERMANN: ".
                        ":ESA2000:CUL_IR:CUL_TX:Revolt:IT:UNIRoll:SOMFY: ".
-                       ":STACKABLE_CC:CUL_RFR::CUL_TCM97001:CUL_REDIRECT:";
-my $clientsHomeMatic = ":CUL_HM:HMS:CUL_IR:STACKABLE_CC:";
-my $clientsMAX       = ":CUL_MAX:HMS:CUL_IR:STACKABLE_CC:";
-my $clientsWMBus     = ":WMBUS:HMS:CUL_IR:STACKABLE_CC:";
-my $clientsKOPP_FC   = ":KOPP_FC:HMS:CUL_IR:STACKABLE_CC:";
+                       ":CUL_RFR: ".
+                       ":CUL_TCM97001:CUL_REDIRECT";  # ToDo TSCUL
+my $clientsHomeMatic = ":CUL_HM:HMS:CUL_IR";          # ToDo TSCUL
+my $clientsMAX       = ":CUL_MAX:HMS:CUL_IR";         # ToDo TSCUL
+my $clientsWMBus     = ":WMBUS:HMS:CUL_IR";           # ToDo TSCUL
+my $clientsKOPP_FC   = ":KOPP_FC:HMS:CUL_IR";         # ToDo TSCUL

my %matchListSlowRF = (
     "1:USF1000"   => "^81..(04|0c)..0101a001a5ceaa00....",
@@ -112,6 +113,7 @@
{
   my ($hash) = @_;

+  require "$attr{global}{modpath}/FHEM/CUL_Util.pm";  # ToDo TSCUL
   require "$attr{global}{modpath}/FHEM/DevIo.pm";

# Provider
@@ -180,7 +183,7 @@
     my $x = $1;
     foreach my $d (keys %defs) {
       next if($d eq $name);
-      if($defs{$d}{TYPE} eq "CUL") {
+      if(IsCULTYPE($defs{$d}{TYPE})) {  # ToDo TSCUL
         if(uc($defs{$d}{FHTID}) =~ m/^$x/) {
           my $m = "$name: Cannot define multiple CULs with identical ".
                         "first two digits ($x)";
@@ -193,7 +196,7 @@
   $hash->{FHTID} = uc($a[3]);
   $hash->{initString} = "X21";
   $hash->{CMDS} = "";
-  $hash->{Clients} = $clientsSlowRF;
+  $hash->{Clients} = PrefixCULCommonClients($clientsSlowRF);  # ToDo TSCUL
   $hash->{MatchList} = \%matchListSlowRF;

   if($dev eq "none") {
@@ -522,9 +525,10 @@
   my ($hash, $arg, $anydata, $regexp) = @_;
   my $ohash = $hash;

-  while($hash->{TYPE} ne "CUL") {   # Look for the first "real" CUL
-    $hash = $hash->{IODev};
-  }
+  while($hash) {  # Look for the first "real" CUL  # ToDo TSCUL
+    last if (IsRealCUL($hash->{TYPE}));            # ToDo TSCUL
+    $hash = $hash->{IODev};                        # ToDo TSCUL
+  }                                                # ToDo TSCUL
   return ("No FD", undef)
         if(!$hash || ($^O !~ /Win/ && !defined($hash->{FD})));

@@ -1036,7 +1040,7 @@
     if($aVal eq "HomeMatic") {
       return if($hash->{initString} =~ m/Ar/);
       if($hash->{CMDS} =~ m/A/ || IsDummy($hash->{NAME}) || !$hash->{FD}) {
-        $hash->{Clients} = $clientsHomeMatic;
+        $hash->{Clients} = PrefixCULCommonClients($clientsHomeMatic);  # ToDo TSCUL
         $hash->{MatchList} = \%matchListHomeMatic;
         CUL_SimpleWrite($hash, "Zx") if ($hash->{CMDS} =~ m/Z/); # reset Moritz
         $hash->{initString} = "X21\nAr";  # X21 is needed for RSSI reporting
@@ -1050,7 +1054,7 @@
     } elsif($aVal eq "MAX") {
       return if($hash->{initString} =~ m/Zr/);
       if($hash->{CMDS} =~ m/Z/ || IsDummy($hash->{NAME}) || !$hash->{FD}) {
-        $hash->{Clients} = $clientsMAX;
+        $hash->{Clients} = PrefixCULCommonClients($clientsMAX);  # ToDo TSCUL
         $hash->{MatchList} = \%matchListMAX;
         CUL_SimpleWrite($hash, "Ax") if ($hash->{CMDS} =~ m/A/); # reset AskSin
         $hash->{initString} = "X21\nZr";  # X21 is needed for RSSI reporting
@@ -1064,7 +1068,7 @@
     } elsif($aVal eq "WMBus_S") {
       return if($hash->{initString} =~ m/brs/);
       if($hash->{CMDS} =~ m/b/ || IsDummy($hash->{NAME}) || !$hash->{FD}) {
-        $hash->{Clients} = $clientsWMBus;
+        $hash->{Clients} = PrefixCULCommonClients($clientsWMBus);  # ToDo TSCUL
         $hash->{MatchList} = \%matchListWMBus;
         $hash->{initString} = "X21\nbrs"; # Use S-Mode
         CUL_WriteInit($hash);
@@ -1076,7 +1080,7 @@
     } elsif($aVal eq "WMBus_T") {
       return if($hash->{initString} =~ m/brt/);
       if($hash->{CMDS} =~ m/b/ || IsDummy($hash->{NAME}) || !$hash->{FD}) {
-        $hash->{Clients} = $clientsWMBus;
+        $hash->{Clients} = PrefixCULCommonClients($clientsWMBus);  # ToDo TSCUL
         $hash->{MatchList} = \%matchListWMBus;
         $hash->{initString} = "X21\nbrt"; # Use T-Mode
         CUL_WriteInit($hash);
@@ -1087,7 +1091,7 @@
       }
     } elsif($aVal eq "KOPP_FC") {
       if($hash->{CMDS} =~ m/k/ || IsDummy($hash->{NAME}) || !$hash->{FD}) {
-        $hash->{Clients} = $clientsKOPP_FC;
+        $hash->{Clients} = PrefixCULCommonClients($clientsKOPP_FC);  # ToDo TSCUL
         $hash->{MatchList} = \%matchListKOPP_FC;
         $hash->{initString} = "krS"; # krS: start Kopp receive Mode
         CUL_WriteInit($hash);
@@ -1099,7 +1103,7 @@

     } else {
       return if($hash->{initString} eq "X21");
-      $hash->{Clients} = $clientsSlowRF;
+      $hash->{Clients} = PrefixCULCommonClients($clientsSlowRF);  # ToDo TSCUL
       $hash->{MatchList} = \%matchListSlowRF;
       $hash->{initString} = "X21";
       CUL_SimpleWrite($hash, "Ax") if ($hash->{CMDS} =~ m/A/); # reset AskSin
@@ -1131,11 +1135,16 @@
{
   my ($isadd, $hash, $msg) = @_;
   my $t = $hash->{TYPE};
-  while($t ne "CUL") {
+#  while(!IsRealCUL($t)) {  # ToDo TSCUL
+#    $msg = CallFn($hash->{NAME}, $isadd ? "AddPrefix":"DelPrefix", $hash, $msg);
+#    $hash = $hash->{IODev};
+#    last if(!$hash);
+#    $t = $hash->{TYPE};
+#  }
+  while($hash) {  # avoid endless loop if $hash is not defined
+    last if (IsRealCUL($hash->{TYPE}));  # ToDo TSCUL
     $msg = CallFn($hash->{NAME}, $isadd ? "AddPrefix":"DelPrefix", $hash, $msg);
     $hash = $hash->{IODev};
-    last if(!$hash);
-    $t = $hash->{TYPE};
   }
   return ($hash, $msg);
}


und 16_STACKABLE_CC.pm

--- org/16_STACKABLE_CC.pm Sun Sep 18 10:19:14 2016
+++ changed/16_STACKABLE_CC.pm Sun Sep 18 10:19:37 2016
@@ -1,5 +1,5 @@
##############################################
-# $Id: 16_STACKABLE_CC.pm 11984 2016-08-19 12:47:50Z rudolfkoenig $
+# $Id: 16_STACKABLE_CC.pm 11984a 2016-08-19 12:47:50Z rudolfkoenig/noansi $
package main;
use strict;
use warnings;
@@ -40,7 +40,7 @@

   my $io = $defs{$a[2]};
   return "$a[2] is not a CUL/STACKABLE_CC"
-    if(!$io || !($io->{TYPE} eq "CUL" || $io->{TYPE} eq "STACKABLE_CC"));
+    if(!$io || !IsCULTYPE($io->{TYPE}));  # ToDo TSCUL

   return "$io->{NAME} has alread a stacked device: $io->{STACKED}"
     if($io->{STACKED});


In der Form überschaubar und leicht wartbar, denke ich. Und die TS-Variante kann nebenher oder auch im Mischbetrieb genutzt werden. Oder hast Du noch eine bessere Idee?

Könnt Ihr bitte diese Änderungen einpflegen und die CUL_Util.pm ergänzen? Damit würde es "updatesicher", nur ein unüberlegter CUL Firmwareupdate kann dann dazwischen funken.

Danke, Ansgar.

rudolfkoenig

Eigentlich lese ich die Wunschliste nicht, aber man hat mich auf diesen Beitrag aufmerksam gemacht.

Was ich nicht verstehe: Wenn durch ein CUL_Util.pm fuer CUL_HM.pm eine Parallelexistenz von 00_TSCUL.pm und 00_CUL.pm ermoeglicht wird, wieso sind Aenderungen in 00_CUL.pm noetig?

noansi

Hallo Rudolf,

es liegt daran, dass SCC beliebig nutzbar sein soll, sprich der Mischbetrieb der Module in einem SCC Stapel sollte möglich sein, was ohne Änderungen scheitert.
Oder es müsste völlig unsinnigerweise ein parallel 00_CULxx und 16_STACKABLE_CCxx Modul geben, was das ermöglicht, ansonsten aber völlig gleiche Funktionalität wie 00_CUL und 16_STACKABLE_CC bietet.

Ansonsten werden die * Nachrichten von SCC nicht oder nicht korrekt weiter gereicht, wenn im SCC Stapel CUL/TSCUL/STACKABLE_CC/TSSTACKED gemischt wird, da jeweils der Modul TYPE relevant ist.

Das Mischen macht dann Sinn, wenn von der einen oder anderen Firmware Funk Protokolle nicht unterstützt werden, die aber genutzt werden möchten.

Natürlich kann man die Abfragen/Ergänzung zu den Modulen auch direkt in 00_CUL.pm und 16_STACKABLE_CC.pm an den verschiedenen Stellen einbauen, aber das ist sehr unübersichtlich und fehleranfällig.
Die angebotene Lösung wäre auch offen für weitere Alterantivmodule.

Gruß, Ansgar.

rudolfkoenig

Sorry fuer die spaete Antwort, bin erst jetzt dazugekommen die Aufgabe naeher anzuschauen.

Ich habe zwei Probleme mit deinem Vorschlag:

- ich will nicht von einem Modul (CUL_Util.pm) abhaengig sein, was durch externe Aenderungen die Funktionalitaet meines Moduls beeintraechtigt.

- ich sehe Bugs in deinem Patch. Oder sagen wir Fragen, vielleicht habe ich was uebersehen:
  - da in 00_CUL.pm MatchList nicht modifiziert wird, wird TSSTACKABLE nie eine Nachricht erhalten. Wie kann man die Nachrichten an TSSTACKABLE von STACKABLE_CC unterscheiden? Vermutlich gar nicht (sonst koennte man das Firmware nicht mischen), und damit muesste ich beide Module in allen MatchLists mit gleichem Regexp auffuehren.
  - "# Look for the first "real" CUL" statt den Letzten macht kein Sinn, es koennen keine 2 CULs im Stack sein.

Ich war bisher der Ansicht, dass die Staerke von deinem culfw-Variante (und damit TSCUL) in der besseren Unterstuetzung von HomeMatic liegt. Weiterhin greift CUL_HM direkt auf CUL Funktionen zu, ist damit nicht faehig STACKABLE_CC, FHEM2FHEM, usw. zu unterstuetzen. Damit waere ein TSSTACKED Unterstuetzung wenig sinnvoll. Vermutlich habe ich eine Entwicklung verschlafen. Kannst du mir bitte sagen, wo?

Will aber keinem im Weg stehen, und habe deswegen die Unterstuetzung von TSCUL und TSSTACKED in meinen beiden Modulen eingebaut, testen konnte ich es nicht. Immerhin ist der Diff klein ausgefallen, was mich freut.
Kannst du es bitte testen und Feedback geben?

noansi

Hallo Rudolf,

danke, dass Du Dich dem annimst!

Zitat- ich will nicht von einem Modul (CUL_Util.pm) abhaengig sein, was durch externe Aenderungen die Funktionalitaet meines Moduls beeintraechtigt.
Muss auch nicht sein, das war nur ein Vorschlag meinerseits, Tests auf unterschiedliche CUL (Modul) Typen zentral unterzubringen -> müsste dann nur dort erweitert oder gewartet werden.
Schon bei CUL_HM wurde STACKABLE_CC nicht abgefragt, eben weil keiner an diesen CUL Typ als HM_IO gedacht hat. Daher der Gedanke.

Zitat- da in 00_CUL.pm MatchList nicht modifiziert wird, wird TSSTACKABLE nie eine Nachricht erhalten
Hmm, guter Hinweis, muss ich mir nochmal ansehen. Ist schon lange her. Aber ich meine, das wäre jeweils über da IODEV oder Stacked device gelöst/zu lösen. Ob das * in der Nachricht über TSSTACKED oder STACKABLE_CC dazu/weg kommt ist dann eigentlich egal.
Nur bei der jeweils passenden CUL/TSCUL Parse Funktion muss die Nachricht ankommen.
Das habe ich vielleicht übersehen in der TSSTACKED und STACKABLE_CC Parse Funktion. Die Parse Funktion zum HASH müsste aufgerufen werden, statt direkt xxx_Parse.
Das muss bei beiden Modulen dann gleich funktionieren.

Zitat- "# Look for the first "real" CUL" statt den Letzten macht kein Sinn, es koennen keine 2 CULs im Stack sein.
??? der Kommentar stammt aus STACKABLE_CC, wenn ich das richtig im Kopf habe.
Und es ging da darum, von "aufgesteckten" Stack Modulen zum untersten durch zu hangeln, der dann als CUL/TSCUL definiert ist. Das first ist vielleicht schlecht im Kommentar.

ZitatIch war bisher der Ansicht, dass die Staerke von deinem culfw-Variante (und damit TSCUL) in der besseren Unterstuetzung von HomeMatic liegt.
Das ist auch mein primärer Fokus.
Aber da ich auch noch einige SlowRF Sensoren nutze und mit dem Empfang noch nicht glücklich war, habe ich da auch dran gedreht. Warten und Slow-RF Sendetiming habe ich auch in der Funktionalität geändert, um sowohl die Kommunikation zum Host zu stabilisieren, als auch das Sendetiming präziser hin zu bekommen.

ZitatWeiterhin greift CUL_HM direkt auf CUL Funktionen zu, ist damit nicht faehig STACKABLE_CC, FHEM2FHEM, usw. zu unterstuetzen. Damit waere ein TSSTACKED Unterstuetzung wenig sinnvoll.
Welche Funktionen meinst Du? So lange das gleiche mit dem HASH passiert, ist das ja kein Problem (bis auf Nebenwirkungen bei Änderungen an CUL).
STACKABLE_CC und TSSTACKED dienen ja eigentlich nur als Hilfs-IO, um die Nachrichten durch den Stapel zu bekommen.
Einige Funktionen zur Sendewarteschlangenverarbeitung in TSSTACKED machen bis auf das Logging auch das gleiche, wie in TSCUL, bzw. werden benötigt, um zur speziellen TSSTACKED Funktion gelangen zu können.

ZitatKannst du es bitte testen und Feedback geben?
Mach ich, dauert aber was.

Gruß, Ansgar.

noansi

Hallo Rudolf,

- "# Look for the first "real" CUL" statt den Letzten macht kein Sinn, es koennen keine 2 CULs im Stack sein.
Aber ich meine, Du musst da auf beide Typen (CUL und TSCUL) testen, denn STACKABLE_CC oder TSSTACKED wissen nicht, wo sie drauf sitzen, wenn sie CUL/TSCUL Funktionen aufrufen, aber direkt oder indirekt ReadAnswer in der jeweiligen Variante ausführen.

In CUL_Define musst Du hier

  if(uc($a[3]) =~ m/^([0-6][0-9A-F])/ && $1 ne "00") {
    my $x = $1;
    foreach my $d (keys %defs) {
      next if($d eq $name);
      if($defs{$d}{TYPE} =~ m/$culNameRe/) {


zumindest auch auf TSSTACKED testen, da TSSTACKED auch eine FHTID haben kann.

Hier habe ich mir was dabei gedacht, erst auf den definierten hash zu testen, weil es mir mal passiert ist, dass der hash undefiniert war und das hat lange gedauert, das Problem zu lokalisieren.
sub
CUL_prefix($$$)
{
  my ($isadd, $hash, $msg) = @_;
  my $t = $hash->{TYPE};
#  while(!IsRealCUL($t)) {  # ToDo TSCUL
#    $msg = CallFn($hash->{NAME}, $isadd ? "AddPrefix":"DelPrefix", $hash, $msg);
#    $hash = $hash->{IODev};
#    last if(!$hash);
#    $t = $hash->{TYPE};
#  }
  while($hash) {  # avoid endless loop if $hash is not defined
    last if (
                ($hash->{TYPE} eq "TSCUL")
             || ($hash->{TYPE} eq "CUL")
            );  # ToDo TSCUL
    $msg = CallFn($hash->{NAME}, $isadd ? "AddPrefix":"DelPrefix", $hash, $msg);
    $hash = $hash->{IODev};


  }

So
    $msg = CallFn($hash->{NAME}, $isadd ? "AddPrefix":"DelPrefix", $hash, $msg);
    $hash = $hash->{IODev};
    last if(!$hash);

wird die Funktion bei undefiniertem hash wieder aufgerufen, bevor auf den hash getestet wird ->  bis der Stack mit am Ende ist und es gibt dann keinen sinnvollen Fehlerhinweis.

Gruß, Ansgar.

rudolfkoenig

ZitatIn CUL_Define musst Du hier.. zumindest auch auf TSSTACKED testen, da TSSTACKED auch eine FHTID haben kann.
Naja, muessen tu ich ja nicht, weiterhin:
- es wird auch nicht auf STACKABLE_CC geprueft
- eine TSSTACKED oder STACKABLE_CC Definition kommt meist nach der CUL Definition, die Pruefung in CUL.pm hilft nicht.
- die Wahrscheinlichkeit dass man bei eiem externen USB-CUL das gleiche FHT-ID vergibt wie auf einem der TSCUL/STACKABLE_CC, ist gering
-> Es bleibt bei der alten Pruefung.

Zitatweil es mir mal passiert ist, dass der hash undefiniert war
Das ist auch nicht normal, STACKABLE_CC prueft bei der Definition, ob es einen passenden IODev gibt.
Habs aber umbgebaut, da es wenig Aufwand ist.


noansi

Hallo Rudolf,

das unterste Modul als CUL für SlowRF definiert (mit CUL_WS Sensoren und ein CUL_TX Sensor)
und darauf ein TSSTACKED als HM IO definiert funktioniert schon mal.

Die Nachrichten kommen in beide Richtungen richtig auch bei den richtigen Modulen an.

Anders rum,
also unterstes Modul als TSCUL HM IO
und darauf ein STACKABLE_CC Modul für SlowRF definiert,
knallts hier bzw. wird endlos schon beim FHEM Start, da Du nicht auch auf TSCUL testest, wie gewünscht, also dann nach TSCUL nur noch undefinertes IODEV und somit dann endlos einen undefinierten hash hast:

sub
CUL_ReadAnswer($$$$)
{
  my ($hash, $arg, $anydata, $regexp) = @_;
  my $ohash = $hash;

  while($hash->{TYPE} ne "CUL") {   # Look for the first "real" CUL
    $hash = $hash->{IODev};
  }


Gruß, Ansgar.

noansi

Hallo Rudolf,

Zitat- da in 00_CUL.pm MatchList nicht modifiziert wird, wird TSSTACKABLE nie eine Nachricht erhalten
ZitatDas habe ich vielleicht übersehen in der TSSTACKED und STACKABLE_CC Parse Funktion. Die Parse Funktion zum HASH müsste aufgerufen werden, statt direkt xxx_Parse.
Die Dispatcherfunktion macht es richtig mit dem Aufruf der TSSTACKED bzw. STACKABLE_CC Parse Funktion, deswegen geht es, da hatte ich mir richtig n'en Kopf drum gemacht.

ZitatAnders rum,
also unterstes Modul als TSCUL HM IO
und darauf ein STACKABLE_CC Modul für SlowRF definiert,
knallts hier bzw. wird endlos schon beim FHEM Start, da Du nicht auch auf TSCUL testest, wie gewünscht, also dann nach TSCUL nur noch undefinertes IODEV und somit dann endlos einen undefinierten hash hast:

So geht es und wird auch nicht endlos, wenn das "reale" IO mal anders lautet.
Zitatsub
CUL_ReadAnswer($$$$)
{
  my ($hash, $arg, $anydata, $regexp) = @_;
  my $ohash = $hash;

  while($hash && $hash->{TYPE} ne "CUL" && $hash->{TYPE} ne "TSCUL") {   # Look for the first "real" CUL
    $hash = $hash->{IODev};
  }

ZitatNaja, muessen tu ich ja nicht
es bezieht sich nur auf, "wenn es funktionieren soll". Ansonsten bist Du frei in Deinem Willen. ;)

Gruß,

Ansgar.

rudolfkoenig

ZitatSo geht es und wird auch nicht endlos, wenn das "reale" IO mal anders lautet.
Danke fuer den Hinweis, habe hier den gleichen Code wie sonst auch verwendet, kannst du es bitte testen?

noansi

Hallo Rudolf,

nun kommen in beiden Testszenarien die Werte richtig an und Befehle gehen richtig raus.
(gestestet # $Id: 00_CUL.pm 12983 2017-01-06 13:53:27Z rudolfkoenig $)

Hier:
sub
CUL_prefix($$$)
{
  my ($isadd, $hash, $msg) = @_;
  while($hash && $hash->{TYPE} !~ m/$culNameRe/) {
    $msg = CallFn($hash->{NAME}, $isadd ? "AddPrefix":"DelPrefix", $hash, $msg);
    $hash = $hash->{IODev};
    last if(!$hash);
  }

ist "    last if(!$hash);" nun überflüssig, da nun eh in der while Bedingung, und Du könntest den noch einsparen.

Die Matchlistergänzung um
    "M:TSSTACKED"=>"^\\*",
müßte eigentlich überflüssig sein. Wenn ich es richtig im Kopf habe wird eh nur der erste erfolgreich gefundene und ausgeführte Match in der Liste ausgeführt, richtig?

Mit Blick auf die IO-Performance wäre
    "H:STACKABLE_CC"=>"^\\*",
als
    "0:STACKABLE_CC"=>"^\\*",
am Anfang der Matchlist besser aufgehoben. Da in der Reihenfolge in der Liste nach dem Match gesucht wird. Und der Match auf "^\\*" ist kurz und schnell im Vergleich zu anderen. (für HM suche ich inzwischen immer jedes bisschen verschwendete Zeit)

Zitat- eine TSSTACKED oder STACKABLE_CC Definition kommt meist nach der CUL Definition, die Pruefung in CUL.pm hilft nicht.
In TSSTACKED ist eine drin.

Gruß und Danke für die Änpassungen!

Ansgar.

rudolfkoenig

Hallo Ansgar,

koenntest Du bitte bei Gelegenheit das neue 16_STACKABLE.pm Modul testen?
Es soll STACKABLE_CC und TSSTACKED abloesen, da generischer ist, und die Weiterreichung der DISCONNECT/CONNECT Events unterstuetzt. Die "Syntax" schaut so aus:

define TSCUL_1 TSCUL /dev/xy 0000

define STACK1 STACKABLE TSCUL_1
define CUL_1 CUL FHEM:DEVIO:STACK1:9600 0000

define STACK2 STACKABLE CUL_1
define TSCUL_2 TSCUL FHEM:DEVIO:STACK2:9600 0000


Du muesstest in TSCUL nur STACKABLE unterstuetzen, die Unterstuetzung fuer STACKABLE_CC und TSSTACKED koennte raus. Ich habe das auch in CUL vor, wenn ich sicher bin, dass STACKABLE funktioniert :)

Gruss,
  Rudi

noansi

Hallo Rudolf,

teste ich.

Muss ich noch weitere Module dafür aktualisieren? Ich bin auf einem 5.7er Stand.

Gruß, Ansgar.

rudolfkoenig

ZitatMuss ich noch weitere Module dafür aktualisieren? Ich bin auf einem 5.7er Stand.
Nach meinem Bauchgefuehl nicht, habs aber nicht getestet.

noansi

Hallo Rudolf,

nach einigen Änderungen bei mir habe ich jetzt mal eine IO-Funktion mit STACKABLE laufen.

Allerdings mußte ich auf mein DevIoTS.pm erst mal verzichten, weil Du DevIo_Disconnected und DevIo_SimpleRead in STACKABLE direkt aufrufst.
Können wir da eine Abfrage auf TSCUL einbauen, damit dann jeweils die DevIoTS Funktions-Variante aufgerufen wird?

In DevIOTS.pm hatte ich einige Änderungen im Bezug auf nicht mehr erreichbare devices einfließen lassen, so dass bei Disconnect z.B. eines CUL Busy Waiting vermieden wird.
Auf die möchte ich höchst ungern verzichten, da es bei HM extrem stört, auch wenn nicht das HM IO device disconnected ist. (Das hat mir mal das System ziemlich lahm gelegt, als ich noch deutliche CUL USB Probleme hatte)

Oder möchtest Du Dir mal mein Lösungsansatz zum Disconnect Busy Waiting näher anschauen und DevIo.pm anpassen?
Statt des Busy Waitings teste ich mittels Timer mehrfach, ob doch noch was vom device kommt, bevor ich wirklich den Status Disconnected setze.

Gruß, Ansgar.

rudolfkoenig

ZitatOder möchtest Du Dir mal mein Lösungsansatz zum Disconnect Busy Waiting näher anschauen und DevIo.pm anpassen?
Kann ich gerne machen, aber vorher moechte ich das Problem verstehen.
Ich frage mich inzwischen, ob du von jeder Datei eine TS Variante hast. :)

noansi

Hallo Rudolf,

ZitatIch frage mich inzwischen, ob du von jeder Datei eine TS Variante hast. :)
Ich arbeite daran.  ;)

In DevIo_SimpleRead($) nutzt Du

  ###########
  # Lets' try again: Some drivers return len(0) on the first read...
  if(defined($buf) && length($buf) == 0) {
    $buf = DevIo_SimpleReadWithTimeout($hash, 1);
  }


was in DevIo_SimpleReadWithTimeout in
  my $nfound = select($rin, undef, undef, $timeout);
bis zu 1 Sekunde Wartezeit erzeugt, wenn das device nicht antwortet.

Für HM muss aber in der Regel innerhalb von 120ms - IO Zeit eine Antwort an das HM IO Device geschickt werden. Das ist eine massive Diskrepanz. Insbesondere wenn FHEM versucht ein anderes nicht antwortendes Device zu neuen Antworten zu bewegen und open dabei nicht scheitert.

  # Lets' try again: Some drivers return len(0) on the first read...

ist mit einem
    $buf = DevIo_SimpleReadWithTimeout($hash, 0);
ebenfalls zu erschlagen.

Nun wollen wir noch wissen, ob das device tot ist.
Also kann man das gleiche auch mit einem Timeout erreichen, der dann bei späteren vergeblichen Aufrufen der Read Funktion zuschlägt und den Disconnected Status setzt. Also Zeitpunkt des ertmaligen vergeblichen zweiten Reads merken und bei "jetzt + x" erneutem vergeblichen Versuch Disconnected setzen oder wenn dann doch etwas kommt, den Timout Startzeitpunkt wieder löschen.

Gruß, Ansgar.

rudolfkoenig

Ich wuerde instinktiv 1 durch 0.01 ersetzen. SimpleRead sollte man nur aufrufen, wenn Select was geliefert hat. Wenn der Kommentar stimmt (weiss leider die genaue Ursache nicht mehr), dann duerfte egal ein, ob man 1s oder 0.01s wartet.

Ich habe das jetzt auch geaendert / eingecheckt.

noansi

#18
Hallo Rudolf,

die bisherigen Tests verlaufen recht gut. Ich  kann aber nur mit CUL im Stack testen

Ich sehe noch ein Problem mit STACKABLE_IOReadFn($), das gelegentlich zuschlägt.

Wenn zum Aufrufzeitpunkt schon asynchrone Daten (z.B. Empfangsdaten) anderer Stackteilnehmer unterwegs sind, dann bekommt der Aufrufer Daten geliefert, die nicht für ihn bestimmt sind (und nimmt sie dem richtigen Empfänger weg).
Das kommt in der Regel selten vor, da "synchronous get" normalerweise selten genutzt wird (IT fällt mir da als Ausnahme ein, wo auf die Rückmeldung zum Sendebefehl gewartet wird).
Beim bisherigen STACKABLE_CC und TSSTACKED habe ich das auch gelegentlich beobachtet, es aber vermutlich fälschlicherweise auf verlorene Zeichen auf der Schnittstelle zurückgeführt. Bei "get credit10ms" etc. habe ich es auch gelegentlich gesehen.

Außerdem können je nach IODev und Auslastung des FHEM Hosts mit einem DevIo_SimpleRead auch noch weitere Daten nach einem '\n' geliefert werden, die nicht in falsche Hände sollen und auch nicht verworfen werden sollten.

Folgender Ansatz zur Verbesserung:
#####################################
sub
STACKABLE_IOReadFn($) # used by synchronous get
{
  my ($hash) = @_;
  my $me = $hash->{IODev};
 
  my $rpf = AttrVal($me->{NAME},"readPrefix","\\*");
  my $srpf = AttrVal($hash->{STACKED},"readPrefix","\\*") if defined($hash->{STACKED});
  my $msrpf = $rpf.$srpf if defined($srpf);

  my $sg = $hash->{helper}{SyncGet};
 
  # we have also to consider asynchronous data from other devices in the stack e.g. received data
  # maybe there is allready partial data in real IODev
  # or complete data not for us
  my $ppart = \$me->{IODev}{PARTIAL}; # IODev has to have and use it!!!
  if (!defined($ppart)) { # but maybe it is not existing yet
    $me->{IODev}{PARTIAL} = "";
    $ppart = \$me->{IODev}{PARTIAL};
  }

  my $buf = ${$ppart};
  ${$ppart} = "";
  my $t;

  while(1) {
    # now we wait for our data or data for one of our stacked devices
    my $to = gettimeofday() + 2;
    $t = "";
    while($buf !~ m/\n/) {
      if (!defined($t) || (gettimeofday() > $to)) {
        ${$ppart} = $buf;
        $hash->{helper}{SyncGet} = 0; # just if client forgets it
        return undef; # undef on error
      }
      $t = DevIo_SimpleRead($me->{IODev}); # may block
      $buf .= $t if (defined($t));
    }

    if ($buf =~ m/^$rpf/) { # is it data for us or one of our stacked devices?

      if (!defined($srpf)) { # not someone stacked?
        # must be for us
        ($buf,$t) = split("\n", $buf, 2); # maybe something more arrived
        $buf .= "\n";
        ${$ppart} .= $t;                  # let IODev handle it later
        last;
      }

      if ($buf !~ m/^$msrpf/) { # not for one of our stacked devices?
        # must be for us
        if ($sg) { # are we the ones waiting for data?
          ($buf,$t) = split("\n", $buf, 2); # maybe something more arrived
          $buf .= "\n";
          ${$ppart} .= $t;                  # let IODev handle it later
          last;
        } else {
          ($t,$buf) = split("\n", $buf, 2); # complete data from IODev for us
          $t .= "\n"; ${$ppart} .= $t;      # let IODev handle it later
          next;
        }
      }

      # must be for one of our stacked devices
      if (!$sg) { # are we not the ones waiting for data?
        ($buf,$t) = split("\n", $buf, 2); # maybe something more arrived
        $buf .= "\n";
        ${$ppart} .= $t;                  # let IODev handle it later
        last;
      }
    }

    # must be for IODev
    ($t,$buf) = split("\n", $buf, 2); # complete data from IODev for stacked device
    $t .= "\n"; ${$ppart} .= $t;      # let IODev handle it later
  }

  $hash->{helper}{SyncGet} = 0; # just if client forgets it
  $buf =~ s/^.//; # Cut off prefix
  if(AttrVal($me->{NAME},"binary",0)) {
    $buf =~ s/[\r\n]//g;
    return pack("H*",$buf);
  } else {
    return $buf;
  }
}


Der Haken: leider muss der Client beim Aufruf sein Flag $hash->{helper}{SyncGet} setzen! Was besseres ist mir bisher leider auf die schnelle nicht eingefallen. Und jeder Client muß {PARTIAL} als Empfangspuffer nutzen (oder es müßte ein Funktion dafür her, diesen zu ermitteln).
Da die Funktion ja rekursiv aufgerufen wird, fehlt mir sonst die Info, ob Daten im Puffer bleiben müssen, damit sie später weiter verarbeitet werden oder geliefert werden müssen. Nur bei 2 Geräten im Stapel ist es eindeutig.
Bei CUL_ReadAnswer mußt Du das Flag vor dem Aufruf von DevIo_SimpleRead setzen. Bei CUL_Read nicht, da es ja nie zur Anwendung kommt bei gestapelten Geräten.
Eine Erweiterung von IOReadFn und DevIo_SimpleRead um ein solches Flag wäre vielleicht ein alterantiver Ansatz.

Zweiter Haken: ich habe selbst nur 2 Geräte im Stapel auf dem PI und kann daher nicht testen, ob mein Code bei mehr Geräten im Stack noch Probleme aufwirft. Kannst Du es testen?

Dritter Haken: es muss auch beim Empfang auf die STACKABLE Kennung geprüft werden. Dafür habe ich noch das Attribut readPrefix mit '*' als default ergänzt. Das ergibt maximale Flexibilität für einen generischen Ansatz.
Da bisher bei synchronous get nicht darauf geprüft wurde, sondern einfach das erste Zeichen entfernt wurde, sind Probleme auch nicht deutlich aufgefallen.

Und nein es ist kein Patch, da die Funktion ohnehin komplett anders ist, als in Deiner Version.  ;)
Ich hoffe, die Kommentare machen einigermaßen klar, wie es gedacht ist.
Mit dem rekursiven Aufruf ist es leider recht mühsam, sich die jeweilen Empfangsdaten und Pufferzustände vorzustellen, um es zu verstehen.

Falldaten sind:
1. Es sind noch komplette und/oder partielle Empfangsdaten im {PARTIAL} des IODev.
2. Während des Wartens auf die gewünschten Antwortdaten kommen noch Daten eines "tieferen" Stackteilnehmers an.
3. Während des Wartens auf die gewünschten Antwortdaten kommen noch Daten eines "höheren" Stackteilnehmers an.
4. Es ist nichts im IODev Empfangspuffer und nur das gewünschte Device sendet seine Antwortdaten. Davon ging die bisherige Implementation aus, was meißtens auch zutrifft.

Gruß, Ansgar.

rudolfkoenig

Kannst du mir das Problem bitte nachstellen? Ich will nicht viel Code einbauen, fuer etwas, was ich weder nachvollziehen, noch testen kann.

Ich habe einen SCC Simulator gebaut (contrib/CULsim.pl), da ich bis vor kurzem gar kein SCC Geraet hatte. Hier kann man im unteren Teil beliebige Antworte auf betimmte Befehle schreiben, es ist auch moeglich spontan irgendwelche Nachrichten zu liefern (siehe #timeout).

noansi

Hallo Rudolf,

mach ich. Den Simulator hatte ich noch nicht entdeckt, danke!

Um nicht auch damit so zufällig testen zu müssen, wie mit der Realität, müßte ich die "bösen" Fälle aber wohl hier bei Antworten einbauen.
      my $msg = "";
           if($cmd eq "V")   { $msg = "V 1.6".length($stars)." CUL868";
      } elsif($cmd eq "T01") { $msg = "0000";
      } elsif($cmd eq "?")   { $msg = "? (? is unknown) Use one of t u x";
      } elsif($cmd eq "t")   { $msg = sprintf("%08X", (time()%86400)*125);
      }


Z.B. für eine simulierte Antwort auf X, bei der ein z.B. *K3107020018\n vor und/oder hinter **211704\n geliefert wird.

Denn nur bei Antworten auf Befehle an SCC wird es problematisch.
Da ich mich mit der SCC Firmware bezüglich Stacking intensiv auseinander gesetzt habe, weiß ich das solche Fälle auftreten können, insbesondere, wenn der FHEM Host stark ausgelastet ist, so dass der Schnittstellenpuffer der seriellen Schnittstelle durch FHEM nicht Zeichen für Zeichen geleert wird.

Gruß, Ansgar

rudolfkoenig

ZitatUm nicht auch damit so zufällig testen zu müssen, wie mit der Realität, müßte ich die "bösen" Fälle aber wohl hier bei Antworten einbauen.
Genau. Ich habe eine Multi-Message Variante mit eingebauten Muell eingecheckt, (siehe Kommentar "Forum #57806")
Haeng hier die geaenderte Variante von CULsim.pl an, dann kann ich dein Problem damit nachstellen.

noansi

#22
Hallo Rudolf,

hier meine Abwandlung von CULSim.pl (auch im Anhang):
#!/usr/bin/perl

# Used for SCC testing.

use strict;
use warnings;
use IO::Socket;
use Time::HiRes qw(gettimeofday);

my $port = "12345";
my $serverSock = IO::Socket::INET->new(
   Listen    => 5,
   LocalAddr => 'localhost',
   LocalPort => $port,
   Proto     => 'tcp',
   ReuseAddr => 1
);

die "Can't open server port: $!" if(!$serverSock);
print "Opened port $port\n";

my %selectlist;
$selectlist{$serverSock->fileno()} = $serverSock;
my $cnt=0;
my $rcnt=0;
my $max_stars = -1; # or set to number of stacked devices to test
my $lstSndTm = gettimeofday();

for(;;) {
  my ($rout,$rin) = ('','');
  map { vec($rin, $_, 1) = 1; } keys %selectlist;
 
  my $now = gettimeofday();
  my $to = ($lstSndTm + ((175.5-0.12)/4)) - $now; # to send periodic messages
  $to = 0 if ($to < 0);
  my $nfound = select($rout=$rin, undef, undef, $to);
  $now = gettimeofday();
  die "select error: $!" if($nfound < 0);

  if(($nfound == 0) && ($max_stars >= 0)) { # timeout
    $cnt++;

    my $msg = "";
    my $n = $cnt % ($max_stars + 1);
    my $c = sprintf("%02X", 0x30-2*$n); # rssi -50 -n
    while($n--) {
      $msg .= '*';
    }
    $msg .= "K31070200" . $c; # by rssi checkable that it arrives at the correct destination
   
    $lstSndTm = $now;
    foreach my $fd (keys %selectlist) {
      if($fd != $serverSock->fileno()) {
        my $h = $selectlist{$fd};
        print "$h->{addr}:$h->{port}: snd >$msg<\n";
        syswrite($h->{sock}, $msg."\r\n");
      }
    }
  }

  foreach my $fd (keys %selectlist) {
    next if(!vec($rout, $fd, 1));
    my $h = $selectlist{$fd};

    if($fd == $serverSock->fileno()) {
      my @clientinfo = $h->accept();
      if(!@clientinfo) {
        print "Accept failed: $!\n";

      } else {
        my ($port, $iaddr) = sockaddr_in($clientinfo[1]);
        my %hash = ( port    => $port,
                     addr    => inet_ntoa($iaddr),
                     sock    => $clientinfo[0],
                     partial => "");
        print "$hash{addr}:$hash{port}: Connect\n";
        $selectlist{$clientinfo[0]->fileno()} = \%hash;
      }

      next;
    }

    my $buf;
    if(sysread($h->{sock}, $buf, 256) <= 0) {
      print "$h->{addr}:$h->{port}: left us\n";
      delete $selectlist{$fd};
      next;
    }

    $buf = $h->{partial} . $buf;
    while($buf =~ m/\n/) {
      $rcnt++;
      my ($cmd, $rest) = split("\n", $buf, 2);
      print "$h->{addr}:$h->{port}: $rcnt rcv >$cmd<\n";
      my $stars;
      $cmd =~ m/^(\**)(.*)$/;
      $stars = $1; $cmd = $2;
     
      my $nstars = length($stars);
      $max_stars = $nstars if ($max_stars < $nstars);
     

      my @msg;
      if($cmd eq "V")  {
        push @msg, "*E01015BE2940100B80B" if($rcnt > 10 &&  $max_stars >= 1); # Forum #57806
        push @msg, $stars."VTS 0.06"." SCCSIM".$nstars; #correct version for TSCUL and to check that it arrives at the correct destination

      } elsif($cmd eq "VH"){
        push @msg, $stars."CUL/SIMTS".$nstars;
        push @msg, "**E01015BE2940100B80B" if($rcnt > 10 &&  $max_stars >= 2);

      } elsif($cmd eq "T01"){
        push @msg, $stars."0000";

      } elsif($cmd eq "?") {
        push @msg, $stars."? (? is unknown) Use one of t u x";

      } elsif($cmd eq "t") {
        push @msg, "**K4107020011" if($rcnt > 10 &&  $max_stars >= 2); #simulate "simultanuous" message before
        push @msg, $stars.sprintf("%08X", (time()%86400)*125);
        push @msg, "*K4107020012" if($rcnt > 10 &&  $max_stars >= 1); #simulate "simultanuous" message after

      } elsif($cmd eq "X") {
        push @msg, "*K4107020013" if($rcnt > 10 &&  $max_stars >= 1); #simulate "simultanuous" message before
        push @msg, $stars.sprintf("21 170").$nstars;
        push @msg, "**K4107020014" if($rcnt > 10 &&  $max_stars >= 2); #simulate "simultanuous" message after

      }
      if(@msg) {
        print "$h->{addr}:$h->{port}:    =>".join(",",@msg)."<\n";
        syswrite($h->{sock}, join("\r\n",@msg)."\r\n"); # CUL sends \r\n
      }

      $buf = $rest;
    }
    $h->{partial} = $buf;

  }
}


Wenn ich mit STACKABLE damit FHEM neu starte, dann schaffe ich nur die Initialisierung von 2 gestapelten simulierten TSCULs bei einem Stapel von >2 TSCULs, weil V und VH nicht die richtigen Antworten zu sehen bekommen. Die oberen bleiben dann auf opened.

Ich habe die simulierten Daten auf K messages umgestellt, da ich in 00_TSCUL und 14_TSCUL_WS dafür eine Statistik eingebaut habe und so sehr schön sehen kann, ob alle Daten beim richtigen simulierten TSCUL ankommen. Mit "get dispSRFStat" kann ich mir die Statistik anschauen.

Gruß, Ansgar.

noansi

#23
Hallo Rudolf,

und hier die geänderte Version von STACKABLE_IOReadFn($), damit auch mehrere Nachrichten auf einmal im Puffer sein dürfen:

#####################################
sub
STACKABLE_IOReadFn($) # used by synchronous get
{
  my ($hash) = @_;
  my $me = $hash->{IODev};
  my $meIOh = $me->{IODev};

  my $rpf = AttrVal($me->{NAME},"readPrefix","\\*");

  my $buf;
 
  if (!defined($hash->{helper}{SyncGet})) { # for compatibility, but not well working
    $buf = "";
    while($buf !~ m/\n/) {
      $buf .= DevIo_SimpleRead($me->{IODev}); # may block
    }
    $buf =~ s/^.//; #cutoff prefix
    #may deliver not (only) the wanted data dependig on the data in the devices buffers
    if(AttrVal($me->{NAME},"binary",0)) {
      $buf =~ s/[\r\n]//g;
      return pack("H*",$buf);
    } else {
      return $buf;
    }
  }

  my $srpf = AttrVal($hash->{STACKED},"readPrefix","\\*") if defined($hash->{STACKED});
  my $msrpf = $rpf.$srpf if defined($srpf);

  my $sg = $hash->{helper}{SyncGet}; # set this flag by the client doing synchronous get
  $hash->{helper}{SyncGet} = 0; # just if client forgets it

  # we have also to consider asynchronous data from other devices in the stack e.g. received data
  # maybe there is allready partial data in real IODev
  # or complete data not for us
  my $ppart = \$meIOh->{PARTIAL}; # IODev has to have and use it!!!
  if (!defined($ppart)) { # but maybe it is not existing yet
    $meIOh->{PARTIAL} = "";
    $ppart = \$meIOh->{PARTIAL};
  }

  $buf = ${$ppart};
  $buf .= DevIo_SimpleRead($meIOh); # may block
  ${$ppart} = "";

  my $ret = "";

  # now check for our data or data for one of our stacked devices
  while($buf =~ m/\n/) {

    my $t;
    ($t,$buf) = split("\n", $buf, 2); # maybe something more arrived
   
    if ($t =~ m/^$rpf/) { # is it data for us or one of our stacked devices?

      if (!defined($srpf)) { # not someone stacked?
        # must be for us
        $t =~ s/^.//;             # Cut off prefix
        $ret .= $t . "\n";
        next;
      }

      if ($t !~ m/^$msrpf/) { # not for one of our stacked devices?
        # must be for us
        if ($sg) { # are we the ones waiting for data?
          $t =~ s/^.//;           # Cut off prefix
          $ret .= $t . "\n";
        } else {
          ${$ppart} .= $t . "\n"; # let IODev handle it later, when it receives new data.
                                  # How can we force a Read for IODev later to avoid the delay until next reception of data?
        }
        next;
      }

      # must be for one of our stacked devices
      if (!$sg) { # are we not the ones waiting for data?
        $t =~ s/^.//;             # Cut off prefix
        $ret .= $t . "\n";
        next;
      }
    }

    # must be for IODev
    ${$ppart} .= $t . "\n";       # let IODev handle it later, when it receives new data
                                  # How can we force a Read for IODev later to avoid the delay until next reception of data?
  }

  ${$ppart} .= $buf; # let IODev handle the remainig later, when it receives new data

  if (defined($meIOh->{helper}{ChkPart}) && (${$ppart} =~ m/\n/)) { # or try to do it now, if IODev supports it
    $meIOh->{helper}{ChkPart} = 1; #IODev needs to support it, this flag inhibits reading from device, just parse {PARTIAL}. IODev needs to clear the flag after!
    CallFn($meIOh->{NAME},"ReadFn",$meIOh); # Parse what arrived at IO
  }

  if(AttrVal($me->{NAME},"binary",0)) {
    $ret =~ s/[\r\n]//g;    #? is binary mode fully covered just here? More than one message can arrive here.
    return pack("H*",$ret); #? is binary mode fully covered just here?
  } else {
    return $ret;
  }
}


Weiterhin benötige ich ein Flag $hash->{helper}{SyncGet}, wie bei der letzten Version, um richtig "auszuschleusen". Damit klappt es und auch die ergänzten Befehle kommen richtig an, sowie auch die "störenden" gleichzeitigen asynchronen Daten.

Außerdem noch unschön, da die nicht benötigten Daten in {PARTIAL} der niedrigeren TSCULs (oder CULs) verbleiben, werden sie erst mit dem nächsten Eintreffen von Daten auch verarbeitet und damit verzögert. Für HM natürlich kontraproduktiv.
Aber leider kann ich Read vom niedrigsten CUL, z.B. mittels Timer, nicht zur Verarbeitung von {PARTIAL} aufrufen, weil das bei leerem Puffer einen Disconnect auslösen müßte ohne Daten im Puffer.

Für TSCUL habe ich folgende Lösung mittels des Flags $hash->{helper}{ChkPart} mit dem TSCUL_Read signalisiert wird, nur den {PARTIAL} zu parsen, aber zuvor nicht vom device zu lesen:

#####################################
# called from the global loop, when the select for hash->{FD} reports data
sub
TSCUL_Read($)
{
  my ($h) = @_;

  my $name = $h->{NAME};

  my $ppart = \$h->{PARTIAL};

  if (!$h->{helper}{ChkPart}) { # just parse {PARTIAL}, needed by STACKABLE
    my $buf = DevIo_SimpleRead($h);
    if(!defined($buf)) {
      TSCUL_condUpdate($h,253);
      Log3 $name, 1, "TSCUL/RAW $name: no data Read";
      return "";  # device disconnected
    }

    Log3 $name, 5, "TSCUL/RAW $name: ${$ppart}/$buf";
    ${$ppart} .= $buf;
  } else {
    $h->{helper}{ChkPart} = 0;
  }

  while(${$ppart} =~ m/\n/) {
    my $rmsg;
    ($rmsg,${$ppart}) = split("\n", ${$ppart}, 2);
    $rmsg =~ s/\r//g;
    TSCUL_Parse($h, $h, $name, $rmsg) if($rmsg);
  }
}


Damit werden dann in STACKABLE_IOReadFn($) erst die asynchronen Daten verarbeitet bevor synchrone Antworten geliefert werden.

Gruß, Ansgar.

noansi

#24
Hallo Rudolf,

hier ein diff zu 00_CUL.pm damit STACKABLE_IOReadFn($) im letzten Edit oben damit zusammenarbeiten kann. Damit habe ich keine Probleme mit der Simulation feststellen können (der Match für X war zu schwach um nicht verwechselt zu werden, daher diese zweite Änderung).

--- E:/tmp/old/00_CUL.pm Tue Mar 28 15:43:16 2017
+++ E:/tmp/new/00_CUL.pm Sun Apr 09 11:51:48 2017
@@ -26,7 +26,7 @@
   "uptime"   => ["t", '^[0-9A-F]{8}[\r\n]*$' ],
   "fhtbuf"   => ["T03", '^[0-9A-F]+[\r\n]*$' ],
   "cmds"     => ["?", '.*Use one of( .)*[\r\n]*$' ],
-  "credit10ms" => [ "X", '^.. *\d*[\r\n]*$' ],
+  "credit10ms" => [ "X", '^[0-9A-F]{2} +\d+[\r\n]*$'], #noansi: STACKABLE more save
);

my %sets = (
@@ -181,6 +181,8 @@
     Log3 undef, 2, $msg;
     return $msg;
   }

+  $hash->{helper}{ChkPart} = 0; # noansi: for STACKABLE

   DevIo_CloseDev($hash);

@@ -437,7 +439,7 @@
       $msg = sprintf("%d %02d:%02d:%02d",
         $msg/86400, ($msg%86400)/3600, ($msg%3600)/60, $msg%60);
     } elsif($a[1] eq "credit10ms") {
-      ($msg) = ($msg =~ /^.. *(\d*)[\r\n]*$/);
+      ($msg) = ($msg =~ /^[0-9A-F]{2} +(\d+)[\r\n]*$/); #noansi: STACKABLE more save
     }

     $msg =~ s/[\r\n]//g;
@@ -570,7 +572,9 @@
       }
       return ("Timeout reading answer for get $arg", undef)
         if($nfound == 0);
+      $ohash->{helper}{SyncGet} = 1; #noansi: STACKABLE
       $buf = DevIo_SimpleRead($hash);
+      $ohash->{helper}{SyncGet} = 0; #noansi: STACKABLE
       return ("No data", undef) if(!defined($buf));

     }
@@ -814,13 +818,20 @@
{
   my ($hash) = @_;

-  my $buf = DevIo_SimpleRead($hash);
-  return "" if(!defined($buf));
   my $name = $hash->{NAME};
-
-  my $culdata = $hash->{PARTIAL};
-  Log3 $name, 5, "CUL/RAW: $culdata/$buf";
-  $culdata .= $buf;
+  my $culdata;

+  if (!$hash->{helper}{ChkPart}) { #noansi: just parse {PARTIAL}, needed by STACKABLE
+    my $buf = DevIo_SimpleRead($hash);
+    return "" if(!defined($buf));
+
+    $culdata = $hash->{PARTIAL};
+    Log3 $name, 5, "CUL/RAW: $culdata/$buf";
+    $culdata .= $buf;
+  } else {                        #noansi: just parse {PARTIAL}, needed by STACKABLE
+    $hash->{helper}{ChkPart} = 0; #noansi: just parse {PARTIAL}, needed by STACKABLE
+    $culdata = $hash->{PARTIAL};
+  }                               #noansi: just parse {PARTIAL}, needed by STACKABLE

   while($culdata =~ m/\n/) {
     my $rmsg;

Auch als Datei im Anhang.

Wenn die beiden zusätzlichen Flags nicht definiert sind, dann fällt STACKABLE_IOReadFn($) in den vorherigen Funktionszustand mit seinen Einschränkungen zurück.

Nur die {PARTIAL} Nutzung ist seitens der Clients und des Basis devices Vorraussetzung.

Unsicher bin ich mir bezüglich des binary Modus, ob das so schon richtig funktioniert.

Was hältst Du von diesem Ansatz?
Hast Du einen besseren Vorschlag?

Gruß, Ansgar.

rudolfkoenig

Weiss nicht ob es besser ist, jedenfalls habe ich jetzt eine modifizierte Version von 16_STACKABLE.pm eingecheckt, der "Muell" bei ReadAnswer wegschmeisst, damit startet ein 4-fach CUL (mit 3-mal STACKABLE dazwischen) mit deiner Version von CULsim.pl problemlos. Es sind nur 5 neue Zeilen dabei, ich meine die Auswirkungen zu verstehen.

Den "Muell" richtig zu parsen benoetigt zu viel Aenderung, und das ist mir fuer diese seltenen Faelle zu risikoreich. Es sei denn jemand legt mir nahe, dass das keine seltenen Faelle sind. Als Muell definiere ich alles, was nicht von der bei ReadAnswer angefragten Ebene kommt.

rudolfkoenig

ZitatUnsicher bin ich mir bezüglich des binary Modus, ob das so schon richtig funktioniert.
Binary wird nur fuer die oberste Ebene unterstuetzt.
Es gibt z.Zt. auch nur ein Anwender dafuer mit einem EnOceanPi auf einem SCC. Theoretisch koennte auch ein Razberry auf einem (oder mehreren) SCCs funktioneren.
Da diese binary Platinen eine Weiterreichung nicht unterstuetzen, braucht STACKABLE das auch nicht zu tun.

noansi

#27
Hallo Rudolf,

hattest Du auch mal get credits10ms getestet?

Dafür war ein Teil des CUL patches gedacht.

Angehängt der reduzierte und noch etwas verfeinerte Patch (3600 max. also mind. 1 Leerzeichen), damit die credits richtig gefiltert werden und nicht mit gleichzeitig eintreffenden sonstigen zum alten match passenden Nachrichten verwechselt werden, wie ich es beobachtet habe.

Zitatder "Muell" bei ReadAnswer wegschmeisst,
SCC ist seriell angebunden. Es liefert also Daten Zeichen für Zeichen und nicht, wie der Simulator Zeilenweise.
Damit müssten auch abgeschnittene Nachrichten am realen SCC Stack auftauchen, die als PARTIAL im untersten CUL vorhanden sein können, bevor der SyncGet von oben startet.
Damit müßten beim untertersten CUL schon mal verstümmelte Nachrichten auftauchen.

Der Simulator müßte dafür modifiziert werden, um auch das als Input simulieren zu können.

Gruß, Ansgar.

noansi

Hallo Rudolf,

ich habe CULSim mal dahingehend abgewandelt, dass auch Teilmessages periodisch geliefert werden können, siehe Anhang. Was periodisch gesendet wird und wo gesplittet wird, kann einfach im Source eingestellt werden.
Was noch fehlt wäre eine Teilnachricht direkt im Anschluss an die gewünschte Antwort im selben Sendepuffer, die mit dem nächsten Sendepuffer vervollständigt wird.

Da Du {PARTIAL} beim untersten SCC nicht beim wegwerfen von "Müll" berücksichtigst, kann z.B. so was passieren:
Zitat2017.04.11 06:24:06.201 5: CUL/RAW: **K310/***K310

Beim Parsen muss das dann ausreichend genau gefiltert werden, damit es keine Probleme bereitet, insbesondere, wenn die neue Message keine * enthält und zudem als Kennbuchstabe eine Hex Ziffer gefolgt von weiteren Zahlen oder Hex Ziffern hat.
Das unangenehme ist, dass es im wahren Leben selten passieren wird und von daher schlecht nachvollziehbar ist.

Mit gelegentlichen Quatsch Nachrichten muss nach meinem Verständnis gerechnet werden.

Gruß, Ansgar.

rudolfkoenig

Bist du _ganz_ sicher, dass solche Nachrichten auftauchen koennen? Ich kenne den SCC nicht so genau, aber culfw sendet eine Nachricht erst, wenn es mit NL abgeschlossen ist, oder der Puffer voll ist. Und der Puffer beim SCC ist mit 512 Byte grosszuegig konfiguriert.

noansi

#30
Hallo Rudolf,

Hier ein Log von einem USB CUL mit tsculfw. Hier wird versucht, erst den USB Buffer zu füllen und dann zu senden, wie Du es meinst.
2017.04.12 06:34:37.599 5: TSCUL/RAW CUL_WS868: /KB739600700D40239_6533266D266D00002C677E062C697E022C70840E2D6A7C022C6B7E022C6B7E022C6A7E04
p 32  856  368  360  856  9  9 7 39
2017.04.12 06:34:37.603 4: TSCUL_Parse: CUL_WS868 KB739600700D40239_6533266D266D00002C677E062C697E022C70840E2D6A7C022C6B7E022C6B7E022C6A7E04 -45.5
2017.04.12 06:34:37.606 5: CUL_WS868: dispatch 810d04xx4027a0017b930670004d20_6533266D266D00002C677E062C697E022C70840E2D6A7C022C6B7E022C6B7E022C6A7E04
2017.04.12 06:34:37.641 5: TSCUL/RAW CUL_WS868: p 32  856  368  360  856  9  9 7 39 / 45 EEE790B7A1084B7484FE  360   0   0

2017.04.12 06:34:37.644 4: TSCUL_Parse: CUL_WS868 p 32  856  368  360  856  9  9 7 39  45 EEE790B7A1084B7484FE  360   0   0
2017.04.12 06:34:57.146 5: SW CUL_WS868: CC0
2017.04.12 06:34:57.152 5: TSCUL/RAW CUL_WS868: /Ci0037032C0002E5D10003A9D8430B000002580000A92F00000585

2017.04.12 06:34:57.172 4: TSCUL_Parse: CUL_WS868 Ci0037032C0002E5D10003A9D8430B000002580000A92F00000585
2017.04.12 06:34:58.264 5: TSCUL/RAW CUL_WS868: /K1149030042_66322C6F2C6F00002D6A7A082E6B78042D6B7A042D6C7A02673408742771840C66340674
p 32  832  400  352  880  9  6 1 42  41 8C665C84217D00  312   0   0

2017.04.12 06:34:58.271 4: TSCUL_Parse: CUL_WS868 K1149030042_66322C6F2C6F00002D6A7A082E6B78042D6B7A042D6C7A02673408742771840C66340674 -41
2017.04.12 06:34:58.273 5: CUL_WS868: dispatch K11490300_66322C6F2C6F00002D6A7A082E6B78042D6B7A042D6C7A02673408742771840C66340674
2017.04.12 06:34:58.329 4: TSCUL_Parse: CUL_WS868 p 32  832  400  352  880  9  6 1 42  41 8C665C84217D00  312   0   0
2017.04.12 06:35:02.748 5: TSCUL/RAW CUL_WS868: /K7162507957_6139267026700000682C0E822D707E082C6B78062D6B76042D6C760266350874672D0C80
p 32  832  392  352  872  9  6 1 57  30 8F52D0D67D9E00  360   0   0

2017.04.12 06:35:02.753 4: TSCUL_Parse: CUL_WS868 K7162507957_6139267026700000682C0E822D707E082C6B78062D6B76042D6C760266350874672D0C80 -30.5
2017.04.12 06:35:02.755 5: CUL_WS868: dispatch K71625079_6139267026700000682C0E822D707E082C6B78062D6B76042D6C760266350874672D0C80
2017.04.12 06:35:02.869 4: TSCUL_Parse: CUL_WS868 p 32  832  392  352  872  9  6 1 57  30 8F52D0D67D9E00  360   0   0
2017.04.12 06:35:09.070 5: TSCUL/RAW CUL_WS868: /K0103425034_68312D702D700000672D0C826C2E08842C6F7E062D6A7808673408762771840A66340676
p 32  832  400  344  880  9  6 1 34  48 88721494358D00  312   0   0


Hier ein Log vom untersten SCC mit tsculfw. Hier wird ab dem ersten Zeichen im seriellen Puffer gesendet, um die Latenz möglichst gering zu halten (serielles Interface):
2017.04.12 06:36:49.955 5: TSCUL/RAW SCC_WS868: /K2102525
2017.04.12 06:36:50.061 5: TSCUL/RAW SCC_WS868: K2102525/116_6335276C633500006236020062350200633500006335000062360200623602006235020063350000276C78002D6A6C0C6634067A662D107E6C2D0E862C6F7A0C653404762670820865340478662D0E822C707C0A652D0E842D69740C6C2D0A826D2D0A842C697A0A6B2D04806D2D06846C2C06826B2D02802D687C0A6B2
2017.04.12 06:36:50.065 5: TSCUL/RAW SCC_WS868: K2102525116_6335276C633500006236020062350200633500006335000062360200623602006235020063350000276C78002D6A6C0C6634067A662D107E6C2D0E862C6F7A0C653404762670820865340478662D0E822C707C0A652D0E842D69740C6C2D0A826D2D0A842C697A0A6B2D04806D2D06846C2C06826B2D02802D687C0A6B2/D027E34636E126C2D027C6C2D027C2D697C04326A78086C2E027A2D647C106B2E00782D697C04336A780A662D0C786D2D067A6C2C047A2D687C08336A780A662D0C7834697608662D0A782D6A78086C2D06782D69
2017.04.12 06:36:50.069 5: TSCUL/RAW SCC_WS868: K2102525116_6335276C633500006236020062350200633500006335000062360200623602006235020063350000276C78002D6A6C0C6634067A662D107E6C2D0E862C6F7A0C653404762670820865340478662D0E822C707C0A652D0E842D69740C6C2D0A826D2D0A842C697A0A6B2D04806D2D06846C2C06826B2D02802D687C0A6B2D027E34636E126C2D027C6C2D027C2D697C04326A78086C2E027A2D647C106B2E00782D697C04336A780A662D0C786D2D067A6C2C047A2D687C08336A780A662D0C7834697608662D0A782D6A78086C2D06782D69/7A066C2D047A6D2D
2017.04.12 06:36:50.073 5: TSCUL/RAW SCC_WS868: K2102525116_6335276C633500006236020062350200633500006335000062360200623602006235020063350000276C78002D6A6C0C6634067A662D107E6C2D0E862C6F7A0C653404762670820865340478662D0E822C707C0A652D0E842D69740C6C2D0A826D2D0A842C697A0A6B2D04806D2D06846C2C06826B2D02802D687C0A6B2D027E34636E126C2D027C6C2D027C2D697C04326A78086C2E027A2D647C106B2E00782D697C04336A780A662D0C786D2D067A6C2C047A2D687C08336A780A662D0C7834697608662D0A782D6A78086C2D06782D697A066C2D047A6D2D/047C2C698006326A
2017.04.12 06:36:50.077 5: TSCUL/RAW SCC_WS868: K2102525116_6335276C633500006236020062350200633500006335000062360200623602006235020063350000276C78002D6A6C0C6634067A662D107E6C2D0E862C6F7A0C653404762670820865340478662D0E822C707C0A652D0E842D69740C6C2D0A826D2D0A842C697A0A6B2D04806D2D06846C2C06826B2D02802D687C0A6B2D027E34636E126C2D027C6C2D027C2D697C04326A78086C2E027A2D647C106B2E00782D697C04336A780A662D0C786D2D067A6C2C047A2D687C08336A780A662D0C7834697608662D0A782D6A78086C2D06782D697A066C2D047A6D2D047C2C698006326A/780A6C2E007A662D
2017.04.12 06:36:50.081 5: TSCUL/RAW SCC_WS868: K2102525116_6335276C633500006236020062350200633500006335000062360200623602006235020063350000276C78002D6A6C0C6634067A662D107E6C2D0E862C6F7A0C653404762670820865340478662D0E822C707C0A652D0E842D69740C6C2D0A826D2D0A842C697A0A6B2D04806D2D06846C2C06826B2D02802D687C0A6B2D027E34636E126C2D027C6C2D027C2D697C04326A78086C2E027A2D647C106B2E00782D697C04336A780A662D0C786D2D067A6C2C047A2D687C08336A780A662D0C7834697608662D0A782D6A78086C2D06782D697A066C2D047A6D2D047C2C698006326A780A6C2E007A662D/0E782D687C06
p
2017.04.12 06:36:50.085 4: TSCUL_Parse: SCC_WS868 K2102525116_6335276C633500006236020062350200633500006335000062360200623602006235020063350000276C78002D6A6C0C6634067A662D107E6C2D0E862C6F7A0C653404762670820865340478662D0E822C707C0A652D0E842D69740C6C2D0A826D2D0A842C697A0A6B2D04806D2D06846C2C06826B2D02802D687C0A6B2D027E34636E126C2D027C6C2D027C2D697C04326A78086C2E027A2D647C106B2E00782D697C04336A780A662D0C786D2D067A6C2C047A2D687C08336A780A662D0C7834697608662D0A782D6A78086C2D06782D697A066C2D047A6D2D047C2C698006326A780A6C2E007A662D0E782D687C06 -63
2017.04.12 06:36:50.088 5: SCC_WS868: dispatch K21025251_6335276C633500006236020062350200633500006335000062360200623602006235020063350000276C78002D6A6C0C6634067A662D107E6C2D0E862C6F7A0C653404762670820865340478662D0E822C707C0A652D0E842D69740C6C2D0A826D2D0A842C697A0A6B2D04806D2D06846C2C06826B2D02802D687C0A6B2D027E34636E126C2D027C6C2D027C2D697C04326A78086C2E027A2D647C106B2E00782D697C04336A780A662D0C786D2D067A6C2C047A2D687C08336A780A662D0C7834697608662D0A782D6A78086C2D06782D697A066C2D047A6D2D047C2C698006326A780A6C2E007A662D0E782D687C06
2017.04.12 06:36:50.186 5: TSCUL/RAW SCC_WS868: p /32  856  368  376  840  9  6 1 16  63 8A5214D6354C80  408   0   0

2017.04.12 06:36:50.189 4: TSCUL_Parse: SCC_WS868 p 32  856  368  376  840  9  6 1 16  63 8A5214D6354C80  408   0   0
2017.04.12 06:36:53.292 5: TSCUL/RAW SCC_WS868: /*AFF0100
2017.04.12 06:36:53.300 5: TSCUL/RAW SCC_WS868: *AFF0100/6A69ED00169786532A133F0000000041
2017.04.12 06:36:53.304 5: TSCUL/RAW SCC_WS868: *AFF01006A69ED00169786532A133F0000000041/01AE42014143006D
2017.04.12 06:36:53.308 5: TSCUL/RAW SCC_WS868: *AFF01006A69ED00169786532A133F000000004101AE42014143006D/44FF933B

2017.04.12 06:36:53.310 5: SCC_WS868: dispatch *AFF01006A69ED00169786532A133F000000004101AE42014143006D44FF933B
2017.04.12 06:36:53.432 5: TSCUL/RAW SCC_WS868: /*AFF01006A69F8001697C6532A133F000000004101AE42014143006D44FF9329

2017.04.12 06:36:53.435 5: SCC_WS868: dispatch *AFF01006A69F8001697C6532A133F000000004101AE42014143006D44FF9329
2017.04.12 06:36:53.485 5: SCC_WS868 sending *As0E1FB011F110342E16750201000000
2017.04.12 06:36:53.486 5: SW SCC_WS868: *As0E1FB011F110342E16750201000000
2017.04.12 06:36:53.881 5: TSCUL/RAW SCC_WS868: /*AFF1300
2017.04.12 06:36:53.885 5: TSCUL/RAW SCC_WS868: *AFF1300/6A6A27020E1FB011
2017.04.12 06:36:53.888 5: TSCUL/RAW SCC_WS868: *AFF13006A6A27020E1FB011/F110342E16750280
2017.04.12 06:36:53.892 5: TSCUL/RAW SCC_WS868: *AFF13006A6A27020E1FB011F110342E16750280/

2017.04.12 06:36:53.895 5: SCC_WS868: dispatch *AFF13006A6A27020E1FB011F110342E16750280
2017.04.12 06:36:54.011 5: TSCUL/RAW SCC_WS868: /*AFF1100
2017.04.12 06:36:54.015 5: TSCUL/RAW SCC_WS868: *AFF1100/6A6AA100111FA002
2017.04.12 06:36:54.019 5: TSCUL/RAW SCC_WS868: *AFF11006A6AA100111FA002/2E1675F1103404BF
2017.04.12 06:36:54.023 5: TSCUL/RAW SCC_WS868: *AFF11006A6AA100111FA0022E1675F1103404BF/DC46D239700413

2017.04.12 06:36:54.025 5: SCC_WS868: dispatch *AFF11006A6AA100111FA0022E1675F1103404BFDC46D239700413
2017.04.12 06:36:54.166 5: TSCUL/RAW SCC_WS868: /*AFF1300
2017.04.12 06:36:54.170 5: TSCUL/RAW SCC_WS868: *AFF1300/6A6ABF01191FA003
2017.04.12 06:36:54.174 5: TSCUL/RAW SCC_WS868: *AFF13006A6ABF01191FA003/F110342E1675EC80
2017.04.12 06:36:54.178 5: TSCUL/RAW SCC_WS868: *AFF13006A6ABF01191FA003F110342E1675EC80/


oder
2017.04.12 06:37:20.662 5: TSCUL/RAW SCC_WS868: /tA07E723
2017.04.12 06:37:20.666 5: TSCUL/RAW SCC_WS868: tA07E723/7242D_9D793D78A1
2017.04.12 06:37:20.669 5: TSCUL/RAW SCC_WS868: tA07E7237242D_9D793D78A1/7500009D7C0E0098
2017.04.12 06:37:20.673 5: TSCUL/RAW SCC_WS868: tA07E7237242D_9D793D78A17500009D7C0E0098/7C1000987B0C003D
2017.04.12 06:37:20.677 5: TSCUL/RAW SCC_WS868: tA07E7237242D_9D793D78A17500009D7C0E00987C1000987B0C003D/78C2009C7A02C23D
2017.04.12 06:37:20.681 5: TSCUL/RAW SCC_WS868: tA07E7237242D_9D793D78A17500009D7C0E00987C1000987B0C003D78C2009C7A02C23D/79C0029B
2017.04.12 06:37:20.685 5: TSCUL/RAW SCC_WS868: tA07E7237242D_9D793D78A17500009D7C0E00987C1000987B0C003D78C2009C7A02C23D79C0029B/7310BCA17808C89B
2017.04.12 06:37:20.689 5: TSCUL/RAW SCC_WS868: tA07E7237242D_9D793D78A17500009D7C0E00987C1000987B0C003D78C2009C7A02C23D79C0029B7310BCA17808C89B/750EBCA2770ACA9D
2017.04.12 06:37:20.693 5: TSCUL/RAW SCC_WS868: tA07E7237242D_9D793D78A17500009D7C0E00987C1000987B0C003D78C2009C7A02C23D79C0029B7310BCA17808C89B750EBCA2770ACA9D/7606C09F7506C43C
2017.04.12 06:37:20.697 5: TSCUL/RAW SCC_WS868: tA07E7237242D_9D793D78A17500009D7C0E00987C1000987B0C003D78C2009C7A02C23D79C0029B7310BCA17808C89B750EBCA2770ACA9D7606C09F7506C43C/79C4024371C20E42
2017.04.12 06:37:20.701 5: TSCUL/RAW SCC_WS868: tA07E7237242D_9D793D78A17500009D7C0E00987C1000987B0C003D78C2009C7A02C23D79C0029B7310BCA17808C89B750EBCA2770ACA9D7606C09F7506C43C79C4024371C20E42/77B8083C75C80A42
2017.04.12 06:37:20.705 5: TSCUL/RAW SCC_WS868: tA07E7237242D_9D793D78A17500009D7C0E00987C1000987B0C003D78C2009C7A02C23D79C0029B7310BCA17808C89B750EBCA2770ACA9D7606C09F7506C43C79C4024371C20E4277B8083C75C80A42/78B80A3B77C60A9E
2017.04.12 06:37:20.709 5: TSCUL/RAW SCC_WS868: tA07E7237242D_9D793D78A17500009D7C0E00987C1000987B0C003D78C2009C7A02C23D79C0029B7310BCA17808C89B750EBCA2770ACA9D7606C09F7506C43C79C4024371C20E4277B8083C75C80A4278B80A3B77C60A9E/7504BEA07504C23C
2017.04.12 06:37:20.713 5: TSCUL/RAW SCC_WS868: tA07E7237242D_9D793D78A17500009D7C0E00987C1000987B0C003D78C2009C7A02C23D79C0029B7310BCA17808C89B750EBCA2770ACA9D7606C09F7506C43C79C4024371C20E4277B8083C75C80A4278B80A3B77C60A9E7504BEA07504C23C/78C6063F
2017.04.12 06:37:20.717 5: TSCUL/RAW SCC_WS868: tA07E7237242D_9D793D78A17500009D7C0E00987C1000987B0C003D78C2009C7A02C23D79C0029B7310BCA17808C89B750EBCA2770ACA9D7606C09F7506C43C79C4024371C20E4277B8083C75C80A4278B80A3B77C60A9E7504BEA07504C23C78C6063F/75C4044377B80A98
2017.04.12 06:37:20.721 5: TSCUL/RAW SCC_WS868: tA07E7237242D_9D793D78A17500009D7C0E00987C1000987B0C003D78C2009C7A02C23D79C0029B7310BCA17808C89B750EBCA2770ACA9D7606C09F7506C43C79C4024371C20E4277B8083C75C80A4278B80A3B77C60A9E7504BEA07504C23C78C6063F75C4044377B80A98/7B0EBA997808B63D
2017.04.12 06:37:20.725 5: TSCUL/RAW SCC_WS868: tA07E7237242D_9D793D78A17500009D7C0E00987C1000987B0C003D78C2009C7A02C23D79C0029B7310BCA17808C89B750EBCA2770ACA9D7606C09F7506C43C79C4024371C20E4277B8083C75C80A4278B80A3B77C60A9E7504BEA07504C23C78C6063F75C4044377B80A987B0EBA997808B63D/7DBE0C997708B49E
2017.04.12 06:37:20.728 5: TSCUL/RAW SCC_WS868: tA07E7237242D_9D793D78A17500009D7C0E00987C1000987B0C003D78C2009C7A02C23D79C0029B7310BCA17808C89B750EBCA2770ACA9D7606C09F7506C43C79C4024371C20E4277B8083C75C80A4278B80A3B77C60A9E7504BEA07504C23C78C6063F75C4044377B80A987B0EBA997808B63D7DBE0C997708B49E/7A0AC09A7708B63E
2017.04.12 06:37:20.732 5: TSCUL/RAW SCC_WS868: tA07E7237242D_9D793D78A17500009D7C0E00987C1000987B0C003D78C2009C7A02C23D79C0029B7310BCA17808C89B750EBCA2770ACA9D7606C09F7506C43C79C4024371C20E4277B8083C75C80A4278B80A3B77C60A9E7504BEA07504C23C78C6063F75C4044377B80A987B0EBA997808B63D7DBE0C997708B49E7A0AC09A7708B63E/7BBC043D72CC14A2
2017.04.12 06:37:20.736 5: TSCUL/RAW SCC_WS868: tA07E7237242D_9D793D78A17500009D7C0E00987C1000987B0C003D78C2009C7A02C23D79C0029B7310BCA17808C89B750EBCA2770ACA9D7606C09F7506C43C79C4024371C20E4277B8083C75C80A4278B80A3B77C60A9E7504BEA07504C23C78C6063F75C4044377B80A987B0EBA997808B63D7DBE0C997708B49E7A0AC09A7708B63E7BBC043D72CC14A2/730CC64472C00C3E
2017.04.12 06:37:20.740 5: TSCUL/RAW SCC_WS868: tA07E7237242D_9D793D78A17500009D7C0E00987C1000987B0C003D78C2009C7A02C23D79C0029B7310BCA17808C89B750EBCA2770ACA9D7606C09F7506C43C79C4024371C20E4277B8083C75C80A4278B80A3B77C60A9E7504BEA07504C23C78C6063F75C4044377B80A987B0EBA997808B63D7DBE0C997708B49E7A0AC09A7708B63E7BBC043D72CC14A2730CC64472C00C3E/79C0043D78C2069D
2017.04.12 06:37:20.744 5: TSCUL/RAW SCC_WS868: tA07E7237242D_9D793D78A17500009D7C0E00987C1000987B0C003D78C2009C7A02C23D79C0029B7310BCA17808C89B750EBCA2770ACA9D7606C09F7506C43C79C4024371C20E4277B8083C75C80A4278B80A3B77C60A9E7504BEA07504C23C78C6063F75C4044377B80A987B0EBA997808B63D7DBE0C997708B49E7A0AC09A7708B63E7BBC043D72CC14A2730CC64472C00C3E79C0043D78C2069D/7902BE9B
2017.04.12 06:37:20.748 5: TSCUL/RAW SCC_WS868: tA07E7237242D_9D793D78A17500009D7C0E00987C1000987B0C003D78C2009C7A02C23D79C0029B7310BCA17808C89B750EBCA2770ACA9D7606C09F7506C43C79C4024371C20E4277B8083C75C80A4278B80A3B77C60A9E7504BEA07504C23C78C6063F75C4044377B80A987B0EBA997808B63D7DBE0C997708B49E7A0AC09A7708B63E7BBC043D72CC14A2730CC64472C00C3E79C0043D78C2069D7902BE9B/7708B83E75C408A1
2017.04.12 06:37:20.752 5: TSCUL/RAW SCC_WS868: tA07E7237242D_9D793D78A17500009D7C0E00987C1000987B0C003D78C2009C7A02C23D79C0029B7310BCA17808C89B750EBCA2770ACA9D7606C09F7506C43C79C4024371C20E4277B8083C75C80A4278B80A3B77C60A9E7504BEA07504C23C78C6063F75C4044377B80A987B0EBA997808B63D7DBE0C997708B49E7A0AC09A7708B63E7BBC043D72CC14A2730CC64472C00C3E79C0043D78C2069D7902BE9B7708B83E75C408A1/7708C49C750ABA44
2017.04.12 06:37:20.756 5: TSCUL/RAW SCC_WS868: tA07E7237242D_9D793D78A17500009D7C0E00987C1000987B0C003D78C2009C7A02C23D79C0029B7310BCA17808C89B750EBCA2770ACA9D7606C09F7506C43C79C4024371C20E4277B8083C75C80A4278B80A3B77C60A9E7504BEA07504C23C78C6063F75C4044377B80A987B0EBA997808B63D7DBE0C997708B49E7A0AC09A7708B63E7BBC043D72CC14A2730CC64472C00C3E79C0043D78C2069D7902BE9B7708B83E75C408A17708C49C750ABA44/77B40A9C7508B8

2017.04.12 06:37:20.760 4: TSCUL_Parse: SCC_WS868 tA07E7237242D_9D793D78A17500009D7C0E00987C1000987B0C003D78C2009C7A02C23D79C0029B7310BCA17808C89B750EBCA2770ACA9D7606C09F7506C43C79C4024371C20E4277B8083C75C80A4278B80A3B77C60A9E7504BEA07504C23C78C6063F75C4044377B80A987B0EBA997808B63D7DBE0C997708B49E7A0AC09A7708B63E7BBC043D72CC14A2730CC64472C00C3E79C0043D78C2069D7902BE9B7708B83E75C408A17708C49C750ABA4477B40A9C7508B8 -51.5
2017.04.12 06:37:20.762 5: SCC_WS868: dispatch TXA07E723724_9D793D78A17500009D7C0E00987C1000987B0C003D78C2009C7A02C23D79C0029B7310BCA17808C89B750EBCA2770ACA9D7606C09F7506C43C79C4024371C20E4277B8083C75C80A4278B80A3B77C60A9E7504BEA07504C23C78C6063F75C4044377B80A987B0EBA997808B63D7DBE0C997708B49E7A0AC09A7708B63E7BBC043D72CC14A2730CC64472C00C3E79C0043D78C2069D7902BE9B7708B83E75C408A17708C49C750ABA4477B40A9C7508B8
2017.04.12 06:37:20.820 5: TSCUL/RAW SCC_WS868: /p  8 1264  952  512  952  4  4 4 2D  51 07E7237240 1240   0   0

2017.04.12 06:37:20.823 4: TSCUL_Parse: SCC_WS868 p  8 1264  952  512  952  4  4 4 2D  51 07E7237240 1240   0   0


Das lange Zeug hinten dran sind Bittimingdaten, wenn das Logging dazu aktiviert ist.
Aber bereits vorne wird gesplittet Empfang "gemeldet".

Es hängt von der FHEM Durchlaufzeit und vom Betreibssystem ab, wann zum ersten mal Empfangsdaten gemeldet werden. Die Stufung zeigt, wie die Teildaten ankommen.
Und es hängt vom Zufall ab, wann ein Sync Get dazwischen haut.

Ein CUNO2 arbeitet beim Netzwerkbetrieb mit TCP/IP Paketen, und daher ähnlich wie USB, also auch in Paketen und nicht Zeichen für Zeichen.

So lange die Puffer nicht überlaufen sorgt die SCC Firmware dafür, dass Sendemessages immer vollständig übertragen werden, ehe eine weitere message gesendet wird, unabhängig davon welches SCC Modul die message sendet.

Gruß, Ansgar.

rudolfkoenig

Ich sehe im Moment keine Probleme mit deinem letzten CULsim.pl, auch wenn ich direkt nach einer Teilmeldung eine Anfrage schicke. K31070200 wird immer als Ganzes weiterverarbeitet, und auch die Antwort auf die Anfrage kommt richtig an.

Teilmeldungen (d.h. ohne NL) koennen nur auf der untersten Ebene passieren, weil Nachrichten ohne NL von CUL_Read bzw. CUL_ReadAnswer nicht an CUL_Parse (und dadurch an die STACKABLE Funktionen) weitergegeben weden. Damit aendert sich wg. STACKABLE nichts, das Problem der Teilnachrichten gab es auch bisher, und wird mW richtig geloest.

Die SCC Firmware muss sicherstellen, dass Nachrichten unterschiedlicher Ebenen nicht gemischt werden. Ob das der Fall ist, weiss ich nicht, aber wenn ja, dann kan man das auf der FHEM-Seite nicht mehr auseinanderdividieren.

An CUL.pm oder STACKABLE.pm sehe ich keinen Aenderungsbedarf.


rudolfkoenig

Korrektur: es gibt ein zusaetzliches Problem im STACKABLE_IOReadFn fur synchrone gets (die hoffentlich Ausnahme sind, da sie FHEM blockieren koennen). Ich habe jetzt in dieser Funktion PARTIAL beruecksichtigt, sie wird aber (da sie zu einer tieferen Ebene gehoert) nicht ausgewertet. Immerhin verwirrt sie nicht mehr beim Empfang der naechsten Nachricht.

noansi

Hallo Rudolf,

ZitatTeilmeldungen (d.h. ohne NL) koennen nur auf der untersten Ebene passieren
Da stimme ich Dir zu.

ZitatDie SCC Firmware muss sicherstellen, dass Nachrichten unterschiedlicher Ebenen nicht gemischt werden.
Bei der tsculfw habe ich eingebaut, dass Raum für ein \r\n im Puffer vorgehalten wird, so dass auch bei einem Pufferüberlauf der Abschluss auch einer unvollständigen Nachricht möglich bleibt. Bei einem einfachen Überlauf innerhalb der Übertragungszeit von 2 Zeichen sollte es sicher sein.
culfw ist da nach meiner Erinnerung unvorsichtiger.
Allerdings wird es normalerweise nur bei so langen Nachrichten, wie ich sie mit dem Bittiming Logging erzeuge auch kritisch mit der Puffergröße.

Hier mein letzter Stand ohne Wegwerfen von "Müll". Mit dieser Variante benötige ich nur noch ein Flag $me->{IODev}{helper}{ChkPart} um die Daten für die unteren Ebenen auch bei Empfang direkt parsen zu können.
Im Cient muss in der ReadFn bei gesetztem Flag nur das Lesen von der Schnittstelle übersprungen werden, so dass alles vollständige in PARTIAL geparst wird.
Wird das Flag von einem Client nicht unterstützt, dann werden dessen asynchrone Daten später erst verarbeitet, wenn neue Daten eintreffen.

#####################################
sub
STACKABLE_IOReadFn($) # used by synchronous get
{
  my ($hash) = @_; # our client, e.g. TSCUL, CUL ...
  my $me = $hash->{IODev};
  my $meIOh = $me->{IODev}; # e.g. TSCUL, CUL ...

  my $rpf = AttrVal($me->{NAME},"readPrefix","\\*");

  my $buf;
 
  my $srpf = AttrVal($hash->{STACKED},"readPrefix","\\*") if defined($hash->{STACKED});
 
  my $sg;
  if (defined($hash->{STACKED})) {
    if (!$defs{$hash->{STACKED}}{SGIS}) {
      $sg = 1; # with us our client is doing sýnchronuos get
    }
  } else {
    $sg = 1; # with us our client is doing sýnchronuos get
  }
  $me->{SGIS} = 1;

  # we have also to consider asynchronous data from other devices in the stack e.g. received data
  # maybe there is allready partial data in real IODev
  # or complete data not for us
  my $ppart = \$meIOh->{PARTIAL}; # IODev has to have and use it! Else it may increase endless !
  if (!defined($ppart)) { # but maybe it is not existing yet
    $meIOh->{PARTIAL} = "";
    $ppart = \$meIOh->{PARTIAL};
  }

  $buf = ${$ppart};
  my $ret = DevIo_SimpleReadWithTimeout($meIOh, 1); # may block
  return undef if(!defined($ret));
  $buf .= $ret;
  ${$ppart} = "";

  $me->{SGIS} = 0;

  $ret = "";

  # now check for our clients data or data for one of our stacked devices
  while($buf =~ m/\n/) {

    my $t;
    ($t,$buf) = split("\n", $buf, 2); # maybe something more arrived

    if ($t =~ m/^$rpf/) { # is it data for our client or one of our stacked devices?

      if (!defined($srpf)) { # not someone stacked?
        # must be for our client
        $t =~ s/^.//;             # Cut off prefix
        $ret .= $t . "\n";
        next;
      }

      if ($t !~ m/^.$srpf/) { # not for one of our stacked devices?
        # must be for our client
        if ($sg) { # are we the one waiting for data?
          $t =~ s/^.//;           # Cut off prefix
          $ret .= $t . "\n";
        } else {
          ${$ppart} .= $t . "\n"; # let IODev handle it later, when it receives new data.
                                  # How can we force a non blocking Read for IODev later to avoid the delay until next reception of data?
        }
        next;
      }

      # must be for one of our stacked devices
      if (!$sg) { # are we not the ones waiting for data?
        $t =~ s/^.//;             # Cut off prefix
        $ret .= $t . "\n";
        next;
      }
    }

    # must be for IODev
    ${$ppart} .= $t . "\n";       # let IODev handle it later, when it receives new data
                                  # How can we force a non blocking Read for IODev later to avoid the delay until next reception of data?
  }

  ${$ppart} .= $buf; # let IODev handle the remainig later, when it receives new data

  if (defined($meIOh->{helper}{ChkPart}) && (${$ppart} =~ m/\n/)) { # or try to do it now, if IODev supports it
    $meIOh->{helper}{ChkPart} = 1; # IODev needs to support it, this flag inhibits reading from device, just parse {PARTIAL}. IODev needs to clear the flag after!
    CallFn($meIOh->{NAME},"ReadFn",$meIOh); # Parse what arrived at IO
  }

  if(AttrVal($me->{NAME},"binary",0)) {
    $ret =~ s/[\r\n]//g;    #? is binary mode fully covered just here? More than one message can arrive here.
    return pack("H*",$ret); #? is binary mode fully covered just here?
  } else {
    return $ret;
  }
}


Was erscheint Dir an diesem Parsen zu riskant? Würde gerade kein SyncGet ausgeführt, würden diese Daten doch auch geparst?!?

CUL_ReadAnswer($$$$) parst auch die asynchronen Daten vor der erwarteten Nachricht!?!

Für TSCUL habe ich mir zum Test in TSCUL_ReadAnswer($$$$) nun auch eingebaut, die vollständigen Daten im Puffer nach der gewünschten Nachricht noch zu parsen. Erst dann wird die Synchrone Antwort geliefert.
Im Bezug auf HM ist eine Empfangsverzögerung für rechtzeitiges Antworten leider maximal kontraproduktiv.

Die Signalisierung mit {SGIS} wäre kritisch, wenn das Parsen der Daten ein weiteres SynchGet auf anderer Ebene auslösen würde.
Allerdings halte ich SynchGet, wie es das IT Modul nutzt, generell in FHEM für fehl am Platz und auch unnötig.

Gruß, Ansgar.

noansi

#34
Hallo Rudolf,

in Zusammenhang mit IT ist mir aufgefallen, dass die Nutzung der GetFn von 00_CUL mit raw durch IT (oder auf FHT) bei gleichzeitigem Empfang anderer Daten im Stack ungünstig enden kann.

GetFn mit raw aufgerufen liefert das erste, was ankommt. Im Stapel kann aber zuerst etwas von einem anderen device ankommen, bevor die erwartete Antwort kommt.

Es fehlt ein Match auf das erwartete Ergebnis (wie bei CUL_ReadAnswer), der aber durch ein weiteres Array Element im Parameter zur GetFn leicht ergänzt werden kann.

Ab Zeile 423 in 00_CUL.pm
  } else {

    CUL_SimpleWrite($hash, $gets{$a[1]}[0] . $arg);
    my $mtch = defined($a[3]) ? $a[3] : $gets{$a[1]}[1]; # optional match for expected result
    ($err, $msg) = CUL_ReadAnswer($hash, $a[1], 0, $mtch);
    if(!defined($msg)) {
      DevIo_Disconnected($hash);
      $msg = "No answer";

    } elsif($a[1] eq "cmds") {       # nice it up


sorgt für eine solche Match Möglichkeit.
Damit kann IT, FHT etc. beim GetFn raw Aufruf entprechend ergänzt werden, um die erwartete Nachricht festzulegen.

Gruß, Ansgar.

rudolfkoenig

ZitatWas erscheint Dir an diesem Parsen zu riskant?

- es ist viel Code, und ich brauche viel Zeit um es (samt Nebeneffekten) zu verstehen.

- ich habe keinen Testfall, um zu pruefen, ob es ein Problem behebt, was die aktuelle Version nicht tut => ich brauche keinen Patch, sondern etwas, was mir das Problem demonstriert.

- es behandelt (mAn) nur selten vorkommende Faelle, falls man get verwendet. Das get im CUL ist blockierend, fuer FHEM ist das Gift, man sollte es meiden. Wenn manche Module darauf angewiesen sind, dann sollte man diese Module umbauen, bevor ich dafuer aufwendige Loesungen einbaue. Eigentlich sollte ich das CUL get auf async umbauen, so wie das im ZWave schon der Fall ist, dann waere diese Diskussion hier auch obsolet.



ZitatAb Zeile 423 in 00_CUL.pm...sorgt für eine solche Match Möglichkeit.
Danke, ich habe es eingecheckt.

noansi

Hallo Rudolf,

ZitatEigentlich sollte ich das CUL get auf async umbauen, so wie das im ZWave schon der Fall ist, dann waere diese Diskussion hier auch obsolet.
Hmm, wie löst das das Problem?

- Das get wird nur verwendet, wenn eine Antwort vom IO erwartet wird.
- Wird die Antwort nicht benötigt, dann kann man das get auch durch ein set ersetzen und den Parser den Müll aussortieren lassen.
- Wird die Antwort aber benötigt, dann ist get die einfachste Methode damit umzugehen, um die zugehörige Antwort zu erhalten und auswerten zu können und wird daher auch von Modulentwicklern gewählt, denke ich.
- Async geht es nur mit Statemachines zur Auswertung der Antwort und Fortsetzung einer Befehlsfolge ans IO.

In jedem Fall muss die Antwort eindeutig auszusortieren sein. Antworten ohne Protokollkennung, also z.B. nur ein Wert, sind dabei ungünstig.
In der Firmware wären daher mAn die ersten Aufräumarbeiten nötig, damit der Parser solche Antworten an die jeweiligen Module weitergeben kann.


Bei STACKABLE_Parse ist mir noch eine Schwäche aufgefallen. In TSCUL habe ich auch readings, die mit gewissen Nachrichten aktualisiert werden.
Bei TSCULs im Stack wird das notify dazu aber nicht ausgelöst, sondern es sammeln sich CHANGED Einträge an.
Das liegt daran, dass immer "" zurück geliefert wird und damit in fhem.pl die CHANGED Daten nicht ausgewertet werden.

    return $ch->{NAME} if (defined($ch->{CHANGED})); # let client notifies device work


in

sub
STACKABLE_Parse($$)
{
  my ($iohash,$msg) = @_;

  return "UNDEFINED $iohash->{NAME}_STACKABLE STACKABLE $iohash->{NAME}"
    if(!$iohash->{STACKED});

  my $name = $iohash->{STACKED};
  return "" if(IsIgnored($name));

  $msg =~ s/^.//; # Cut off prefix *, dispatcher "verified" it
  my $sh = $defs{$name};

  my $ch = $sh->{".clientHash"};
  if($ch) {
    delete $ch->{IOReadFn};
    $ch->{IODevRxBuffer} = (AttrVal($name,"binary",0) ?
                                pack("H*",$msg) : $msg."\n");
    CallFn($ch->{NAME}, "ReadFn", $ch);
    $ch->{IOReadFn} = "STACKABLE_IOReadFn";
    return $ch->{NAME} if (defined($ch->{CHANGED})); # let client notifies device work
  } else {
    Log 1, "STACKABLE_Parse $name: no client device assigned";
  }
  return "";
}


sorgt dafür, das CHANGED verarbeitet wird und Notifies ausgelöst werden.

Als nicht erwünschter Nebeneffekt werden dabei aber auch MSGCNT und .*_MSGCNT im device erhöht. Um das zu beheben müsste ein zusätzliches Flag von fhem.pl unterstützt werden, das diese MSGCNT Updates unterdrückt.

Gruß, Ansgar.

noansi

Hallo Rudolf,

bist Du Dir bewusst, dass

my $v = 1 if (condition);

nicht immer das gleiche in $v erzeugt, wie

my $v;
$v = 1 if (condition(;


wenn die condition nicht true ist?

Mir ist das jetzt unangenehm aufgefallen beim rekursiven Aufruf in STACKABLE.
Es wurde dabei statt undef etwas in $v gesetzt, was zuvor mal drin stand. Sehr unangenehm zu finden!

Daher folgender Patchvorschlag und Verzichtsanregung auf die abkürzende Schreibweise my mit Bedingung.

--- old/fhem.pl Mon May 01 09:07:22 2017
+++ new/fhem.pl Wed May 10 21:01:56 2017
@@ -27,7 +27,7 @@
#
#  Homepage:  http://fhem.de
#
-# $Id: fhem.pl 14152 2017-05-01 09:07:23Z rudolfkoenig $
+# $Id: fhem.pl 14097 2017-04-24 11:50:40Z rudolfkoenig $


use strict;
@@ -239,7 +239,7 @@
use vars qw(@structChangeHist); # Contains the last 10 structural changes

$selectTimestamp = gettimeofday();
-$cvsid = '$Id: fhem.pl 14152 2017-05-01 09:07:23Z rudolfkoenig $';
+$cvsid = '$Id: fhem.pl 14097 2017-04-24 11:50:40Z rudolfkoenig $';

my $AttrList = "alias comment:textField-long eventMap group room ".
                "suppressReading userReadings:textField-long ".
@@ -1732,7 +1732,9 @@
   if(defined($hash->{".triggerUsed"}) && $hash->{".triggerUsed"} == 0) {
     shift @a;
     # set arg if the module did not triggered events
-    my $arg = join(" ", @a) if(!$hash->{CHANGED} || !int(@{$hash->{CHANGED}}));
+#    my $arg = join(" ", @a) if(!$hash->{CHANGED} || !int(@{$hash->{CHANGED}}));
+    my $arg;
+    $arg = join(" ", @a) if(!$hash->{CHANGED} || !int(@{$hash->{CHANGED}}));
     DoTrigger($dev, $arg, 0);
   }
   delete($hash->{".triggerUsed"});
@@ -3807,8 +3809,12 @@
                   map { $_ =~ s/.*?=//s; $_ =~ s/.*?://s; "$_:noArg" } @emList);
   }

-  my $dname = shift @{$str} if(!$dir);
-  my $nstr = join(" ", @{$str}) if(!$dir);
+#  my $dname = shift @{$str} if(!$dir);
+  my $dname;
+  $dname = shift @{$str} if(!$dir);
+#  my $nstr = join(" ", @{$str}) if(!$dir);
+  my $nstr;
+  $nstr = join(" ", @{$str}) if(!$dir);

   my $changed;
   foreach my $rv (@emList) {
@@ -4235,14 +4241,20 @@
       } elsif($modifier eq "difference") {
         $result= $value - $oldvalue if(defined($oldvalue));
       } elsif($modifier eq "differential") {
-        my $deltav= $value - $oldvalue if(defined($oldvalue));
-        my $deltat= $hash->{".updateTime"} - $oldt if(defined($oldt));
+#        my $deltav= $value - $oldvalue if(defined($oldvalue));
+        my $deltav;
+        $deltav= $value - $oldvalue if(defined($oldvalue));
+#        my $deltat= $hash->{".updateTime"} - $oldt if(defined($oldt));
+        my $deltat;
+        $deltat= $hash->{".updateTime"} - $oldt if(defined($oldt));
         if(defined($deltav) && defined($deltat) && ($deltat>= 1.0)) {
           $result= $deltav/$deltat;
         }
       } elsif($modifier eq "integral") {
         if(defined($oldt) && defined($oldvalue)) {
-          my $deltat= $hash->{".updateTime"} - $oldt if(defined($oldt));
+#          my $deltat= $hash->{".updateTime"} - $oldt if(defined($oldt));
+          my $deltat;
+          $deltat= $hash->{".updateTime"} - $oldt if(defined($oldt));
           my $avgval= ($value + $oldvalue) / 2;
           $result = ReadingsVal($name,$reading,$value);
           if(defined($deltat) && $deltat>= 1.0) {


Die Perl Doku weist auch in einer Note auf das nicht definierte Verhalten dieses my ... if Konstrukts hin.
Im Bereich um Zeile 1732 oder 4235 hat es in alter Form bei meinen STACKABLE Tests auch Quatsch gemacht, wie ich an den MSGCNT Zählwerten gesehen habe.

Gruß, Ansgar.

noansi

Hallo Rudolf,

hier noch ein verbesserter Ansatz für STACKABLE_IOReadFn($).

#####################################
sub
STACKABLE_IOReadFn($) # used by synchronous get
{
  my ($hash) = @_; # our client, e.g. TSCUL, CUL ...
  my $myhash = $hash->{IODev};
  my $myIOh = $myhash->{IODev}; # e.g. TSCUL, CUL ...

  Log3 $myhash->{NAME}, 0, "STACKABLE_IOReadFn $myhash->{NAME}: bad recursive call detected!" if ($myhash->{IORM} ne "");

  my $m; # do not use  "my $m = $defs{$hash->{STACKED}}{IORM} if (defined($hash->{STACKED}));" That results in strange recursive behaviour!
  $m = $defs{$hash->{STACKED}}{IORM} if (defined($hash->{STACKED}));
  $m .= "\\*";

  $myhash->{IORM} = $m; # set our "trace" down the stack

  my $ret = DevIo_SimpleReadWithTimeout($myIOh, 1); # may block for 1 second each call
                                                    # will call STACKABLE_IOReadFn recursivly
                                                    # down to the first CUL in stack
                                                    # this may also modify it's {PARTIAL} buffer
                                                    # by parsing

  $myhash->{IORM} = ""; # reset before any return, not to break the recursive reset!

  return undef if(!defined($ret));

  # we have also to consider asynchronous data from other devices in the stack e.g. received data
  # maybe there is allready partial data in real IODev
  # or complete data not for us
  my $pIOpart = \$myIOh->{PARTIAL}; # IODev has to have and use it! Else it may increase endless !

  my $buf = ${$pIOpart};

#  Log3 $myhash->{NAME}, 5, "TSCUL $myIOh->{NAME}/RAW $myhash->{NAME} match:$m pre: $buf/$ret";

  $buf .= $ret;
  ${$pIOpart} = "";

  $ret = "";

  # now check for our clients data or data for one of our stacked devices
  while($buf =~ m/\n/) {

    my $t;
    ($t,$buf) = split("\n", $buf, 2); # maybe something more arrived

    if ($t =~ m/^$m[^\*]/) { # is it data we are looking for for the requesting stack member?
      $t =~ s/^.//;      # Cut off prefix
      $ret .= $t . "\n"; # deliver to next stack level
      next;
    }

    # must be for IODev or should be handled by IODev
    ${$pIOpart} .= $t . "\n"; # let IODev handle it later, when it receives new data
  }

  ${$pIOpart} .= $buf; # let IODev handle the remainig later, when it receives new data

#  Log3 $myhash->{NAME}, 5, "TSCUL $myIOh->{NAME}/RAW $myhash->{NAME} ret: ${$pIOpart}/$ret";

  if ((${$pIOpart} =~ m/\n/) && defined($myIOh->{helper}{ChkPart}) && $init_done) { # let IODev handle it's data now, if IODev supports it
    $myIOh->{helper}{ChkPart} = 1; # IODev needs to support this flag.
                                   # This flag inhibits reading from device, just parse {PARTIAL}.
                                   # IODev needs to clear the flag after!
                                   # See TSCUL_Read($) for a usage example for implementing
                                   # and add a line "$hash->{helper}{ChkPart} = 0;" in define function
                                   # as in TSCUL_Define($$)
    CallFn($myIOh->{NAME},"ReadFn",$myIOh); # Parse what arrived at IO, avoid long async reception delays!
                                            # normaly only at bottom of stack this is executed
                                            # cause only there data should remain in ${$pIOpart}
                                            # this way they are parsed in order except the messages
                                            # for the requesting stack member
  }

  if(AttrVal($myhash->{NAME},"binary",0)) {
    $ret =~ s/[\r\n]//g;    # binary mode is only allowed for a device on top of stack!!!
    return pack("H*",$ret); # else we may get in trouble here,
                            # if more than one message arrives with
                            # messages also for stacked devices
  } else {
    return $ret;
  }
}


{IORM} muss noch in STACKABLE_Define($$) mit "" vorbelegt werden.

Es wird ein * Matchmuster bis nach unten im Stack gebildet und dort dann gezielt aus den ankommenden Daten passende Nachrichten für das anfordernde Device extrahiert.
Damit bleibt die Nachrichtenreihenfolge für asynchrone Daten anderer devices im Stack erhalten, was in meinen vorherigen Ansätzen nicht der Fall war.
Und diese können unten per Dispatch auch direkt verarbeitet werden, mit kleiner Ergänzung am IODev.
Damit würden dann für andere devices im Stack keine Nachrichtenverluste auftreten und die Empfangsreihenfolge nebst Empfangszeitpunkt blieben für diese auch erhalten.
Wenn das IODev nicht für den Dispatch modifiziert wird, dann werden die Daten mit den nächsten asynchronen Daten für eines der Stackdevices verzögert verarbeitet, was ich schlechter finde.

Nur das pollende Modul im Stack würde die Antwort, auf die es ohnehin wartet, ggf. etwas verzögert bekommen.

Eine Log Meldung ist auch drin, um festzustellen, ob böse rekursive Aufrufe durch das Dispatchen auftreten.

Gruß, Ansgar.

rudolfkoenig

Zitatbist Du Dir bewusst, dass...
Inzwischen schon, ich musste vor (gefuehlt) einem Jahr eine Stelle deswegen anpassen.
Mir ist nur in diesen Faellen noch nicht klar, warum es zu einem Problem fuehrt.

Zitathier noch ein verbesserter Ansatz für STACKABLE_IOReadFn($).
Ich glaube, wir drehen uns im Kreis. Wie ich das vor zwei Wochen schon geschrieben habe: ich brauche keinen Patch, sondern etwas, was mir das Problem demonstriert.

noansi

Hallo Rudolf,

ZitatMir ist nur in diesen Faellen noch nicht klar, warum es zu einem Problem fuehrt.

Auf perldoc http://perldoc.perl.org/perlsyn.html#Compound-Statements findest Du:

ZitatNOTE: The behaviour of a my, state, or our modified with a statement modifier conditional or loop construct (for example, my $x if ... ) is undefined. The value of the my variable may be undef, any previously assigned value, or possibly anything else. Don't rely on it. Future versions of perl might do something different from the version of perl you try it out on. Here be dragons.

Daher fällt dies bei mir unter vorrausschauende Bug Vermeidung, alle diese Konstrukte in eine semantisch eindeutige und sichere Form umzuschreiben. Oder hast Du Lust, nach einem Perl Update ggf. merkwürdige Nebeneffekte zu suchen und zu korrigieren? Oder wenn nur jemand oder Du selbst eine Funktion mal rekursiv nutzt?

Beim Dispatch Versuch in STACKABLE ist es mir nicht als drastisches Problem aufgefallen. Aber die MSGCNT Zähler, die ich mit der geänderten Rückgabe in STACKABLE_Parse bei vorhandenen {CHANGED} Einträgen indirekt über Dispatch aktiviert hatte (siehe oben), haben Quatsch gezählt. Im ersten gestapelten Device wurde gezählt, was in höheren hätte gezählt werden müssen. Ob noch mehr dadurch Schief gelaufen ist, kann ich nicht sagen und habe ich auch nicht untersucht.

Es ist halt eine böse Falle, ebenso, wie ein versehentlich vergessenes oder gelöschtes"my" bei einer lokalen Variablen Deklaration bei dem Perl dann u.U. eine andere existierende lokale Variable nutzt. Schwer zu finden oder nachzuvollziehen, erst recht, wenn eine Funktion lange Zeit tadellos funktioniert hat.


ZitatIch glaube, wir drehen uns im Kreis. Wie ich das vor zwei Wochen schon geschrieben habe: ich brauche keinen Patch, sondern etwas, was mir das Problem demonstriert.
Ich habe Dir in realen Logs gezeigt, dass lange Nachrichten im Puffer auftauchen können, wenn FHEM lange mit z.B. Notify Abarbeitung beschäftigt ist. Ebenso können also auch mehrere Nachrichten im Puffer auflaufen, bis FHEM Zeit für die Verabeitung hat.
Wenn eine HM Nachricht mit Antwortflag dabei ist, die noch nicht zu lange darin verweilt, dann besteht die Chance, sie noch rechtzeitig seitens FHEM zu beantworten, und das möchte ich.

Selbst wenn ich Dir das jetzt im Simulator ein entsprechndes Konstrukt einbaue, wirst Du mir immer noch sagen, dass es ein seltener Fall ist, den Du meinst in Kauf nehmen zu können. In den meisten Fällen wird das auch so sein, da HM devices normalerweise auch wiederholen.
Ich empfange im Stack auch WS2000 Sensordaten. Da wird nicht wiederholt und der Empfang ist ohnehin gerne mit Verlusten behaftet. Da möchte ich ebenfalls möglichst keine Daten verlieren und benötige auch die einigermaßen korrekte Empfangszeit.
Wenn es im realen Leben also gerade mal "passiert" habe ich bestimmt gerade nicht das passende Logging laufen, um es Dir auf dem Weg nachweisen zu können.

Für mich geht es also darum, ob Du mit meinen Änderungswunsch doch noch mitgehst oder ob ich von STACKABLE (und auch DeviceIo) wieder eine TS Variante bauen muss, um dahin zu kommen (was ja eigentlich gegen den Sinn dieser beiden ist).

STACKABLE finde ich grundsätzlich super und eine wesentliche Verbesserung gegenüber der alten Lösung, Danke dafür!
Und natürlich ausbaufähig auch für andere IOs die so ein Protokoll nutzen. Datenverluste stören mich dagegen, insbesondere dann, wenn ich sie gerade doch mal nicht brauchen kann.

Gruß, Ansgar.

rudolfkoenig

ZitatMir ist nur in diesen Faellen noch nicht klar, warum es zu einem Problem fuehrt..
Ich habe das Gefuehl, dass du diese Frage indirekt mit "nein" bzw. "weiss nicht" beantwortet hast, korrigiere mich, wenn ich falsch liege. Ich habe die Stellen angepasst, einerseits weil ich relativ sicher bin, kein Problem dadurch zu verursachen, andererseits weil ich dich nicht unnoetig aergern will.


ZitatFür mich geht es also darum, ob Du mit meinen Änderungswunsch doch noch mitgehst
Nein, da an solchen stellen der Kode von mir stammen muss, damit ich es auch nach eine Weile verstehe und ihn warten kann. Natuerlich bin ich weiterhin bereit, nachstellbare Probleme zu beheben.

noansi

Hallo Rudolf,

ZitatIch habe das Gefuehl, dass du diese Frage indirekt mit "nein" bzw. "weiss nicht" beantwortet hast
Ich weiß nicht, ob die "my if" Korrektur, außer dem durch meine zusätzliche Dispatcherei aufgefallenen _MSGCNT Fehlverhalten, weitere Probleme löst und habe es auch bisher nicht untersucht.
Mir ist aber aufgefallen, dass ich seit dem noch keine merkwürdige HM Wiederholungen durch 10_CUL_HM gesehen habe, die ich mir bisher nicht erklären kann (und wegen des Seltenheitswerts auch nicht in Rohdaten loggen konnte). In 10_CUL_HM habe ich natürlich auch direkt dieses Konstrukt gesucht und umgebaut. Die Testzeit ist aber noch zu kurz, um wirklich empirisch auf eine Verbesserung zu schließen.
Wenn Du meinst, dass ich meine, dass Du die Frage so beantwortet hast, dann liegst Du falsch. Ich habe nur gelernt, dass es teilweise schwierig bis unmöglich ist, eine aus meiner Sicht sinnvolle oder nützliche Änderung zu bewirken, ohne konkretes Fehler-/Problemlog sondern nur mit reiner Überlegung oder empirischer Erfahrung. In diesem Fall war die Hoffnung größer wegen der PerlDoc Note.
Dafür bin ich auch immer wieder überrascht, welche Alternativlösungen dabei teilweise raus kommen.

ZitatIch habe die Stellen angepasst, einerseits weil ich relativ sicher bin, kein Problem dadurch zu verursachen, andererseits weil ich dich nicht unnoetig aergern will.
Danke!
Ärgern tue ich mich aber nicht. Es ist nur insbesondere bei fhem.pl ein großer Aufwand ein fhem upate mitzuziehen, wenn ich dann meine Änderungen wieder nachziehen muss.
Seit meinem ersten Versuch eine Empfangstimestamp in fherm.pl unterzubringen, meide ich Eingriffe in fhem.pl eigentlich.
Ich hoffe Du ärgerst Dich nicht, wenn ich es immer wieder teilweise etwas hartnäckig (und dann auch noch in für Dich suboptimaler Form) versuche, Dich von einer Änderung zu überzeugen.

ZitatNein, da an solchen stellen der Kode von mir stammen muss, damit ich es auch nach eine Weile verstehe und ihn warten kann.
Ok und kein Problem. Solltest Du STACKABLE und DeviceIo doch noch mal sinngemäß gleichziehen wollen oder müssen, wäre es schön doch auf einen gemeinsamen Stand zu kommen, um meine Variante sterben zu lassen.
Das geht mir genauso, dass fremder Code häufig schlechter zu verstehen ist. Nach längerer Zeit auch der eigene. ;)

Gruß, Ansgar.

noansi

Hallo Rudolf,

ZitatIch habe die Stellen angepasst
Hmm, aber nicht alle?!

Hier das diff dazu:
--- old/fhem.pl Fri May 12 05:48:16 2017
+++ new/fhem.pl Sat May 13 10:11:10 2017
@@ -27,7 +27,7 @@
#
#  Homepage:  http://fhem.de
#
-# $Id: fhem.pl 14252 2017-05-12 05:48:17Z rudolfkoenig $
+# $Id: fhem.pl 14097 2017-04-24 11:50:40Z rudolfkoenig $


use strict;
@@ -239,7 +239,7 @@
use vars qw(@structChangeHist); # Contains the last 10 structural changes

$selectTimestamp = gettimeofday();
-$cvsid = '$Id: fhem.pl 14252 2017-05-12 05:48:17Z rudolfkoenig $';
+$cvsid = '$Id: fhem.pl 14097 2017-04-24 11:50:40Z rudolfkoenig $';

my $AttrList = "alias comment:textField-long eventMap group room ".
                "suppressReading userReadings:textField-long ".
@@ -3808,7 +3808,9 @@
                   map { $_ =~ s/.*?=//s; $_ =~ s/.*?://s; "$_:noArg" } @emList);
   }

-  my $dname = shift @{$str} if(!$dir);
+#  my $dname = shift @{$str} if(!$dir);
+  my $dname;
+  $dname = shift @{$str} if(!$dir);
   my $nstr;
   $nstr = join(" ", @{$str}) if(!$dir);

@@ -4237,14 +4239,20 @@
       } elsif($modifier eq "difference") {
         $result= $value - $oldvalue if(defined($oldvalue));
       } elsif($modifier eq "differential") {
-        my $deltav= $value - $oldvalue if(defined($oldvalue));
-        my $deltat= $hash->{".updateTime"} - $oldt if(defined($oldt));
+#        my $deltav= $value - $oldvalue if(defined($oldvalue));
+        my $deltav;
+        $deltav= $value - $oldvalue if(defined($oldvalue));
+#        my $deltat= $hash->{".updateTime"} - $oldt if(defined($oldt));
+        my $deltat;
+        $deltat= $hash->{".updateTime"} - $oldt if(defined($oldt));
         if(defined($deltav) && defined($deltat) && ($deltat>= 1.0)) {
           $result= $deltav/$deltat;
         }
       } elsif($modifier eq "integral") {
         if(defined($oldt) && defined($oldvalue)) {
-          my $deltat= $hash->{".updateTime"} - $oldt if(defined($oldt));
+#          my $deltat= $hash->{".updateTime"} - $oldt if(defined($oldt));
+          my $deltat;
+          $deltat= $hash->{".updateTime"} - $oldt if(defined($oldt));
           my $avgval= ($value + $oldvalue) / 2;
           $result = ReadingsVal($name,$reading,$value);
           if(defined($deltat) && $deltat>= 1.0) {


Hat der patch nicht funktioniert?

Gruß, Ansgar.

rudolfkoenig

Hab diese jetzt auch geaendert.