2
0
mirror of https://github.com/fhem/fhem-mirror.git synced 2025-03-13 11:16:36 +00:00

repeater bugfix, HM manual mode, protocol cleanup

git-svn-id: https://svn.fhem.de/fhem/trunk@4135 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
martinp876 2013-10-30 10:07:00 +00:00
parent d9e009a5a7
commit a1defcef2a
3 changed files with 92 additions and 49 deletions

View File

@ -115,7 +115,6 @@ sub CUL_HM_putHash($);
# ----------------modul globals----------------------- # ----------------modul globals-----------------------
my $respRemoved; # used to control trigger of stack processing my $respRemoved; # used to control trigger of stack processing
my $IOpoll = 0.2;# poll speed to scan IO device out of order my $IOpoll = 0.2;# poll speed to scan IO device out of order
my $IOpolltout = 60; # poll timeout - stop poll and discard if to late
my $maxPendCmds = 10; #number of parallel requests my $maxPendCmds = 10; #number of parallel requests
@ -144,8 +143,6 @@ sub CUL_HM_Initialize($) {
"param msgRepeat ". "param msgRepeat ".
".stc .devInfo ". ".stc .devInfo ".
$readingFnAttributes; $readingFnAttributes;
$hash->{hmAutoReadScan} = 4; # delay autoConf readings
#autoReadReg: #autoReadReg:
# ,6_allForce # ,6_allForce
# ,4_backUpdt # ,4_backUpdt
@ -166,6 +163,9 @@ sub CUL_HM_Initialize($) {
$hash->{helper}{qReqConf} = \@confQArr; $hash->{helper}{qReqConf} = \@confQArr;
$hash->{helper}{qReqConfWu} = \@confQWuArr; $hash->{helper}{qReqConfWu} = \@confQWuArr;
CUL_HM_initRegHash(); CUL_HM_initRegHash();
$hash->{hmIoMaxDly} = 60;# poll timeout - stop poll and discard
$hash->{hmAutoReadScan} = 4; # delay autoConf readings
$hash->{helper}{hmManualOper} = 0;# default automode
} }
sub CUL_HM_updateConfig($){ sub CUL_HM_updateConfig($){
@ -1615,10 +1615,12 @@ sub CUL_HM_parseCommon(@){#####################################################
$ret = $reply; $ret = $reply;
} }
elsif($mTp eq "00"){###################################### elsif($mTp eq "00"){######################################
CUL_HM_infoUpdtDevData($shash->{NAME}, $shash,$p);#update data
my $iohash = $shash->{IODev}; my $iohash = $shash->{IODev};
my $id = CUL_HM_Id($iohash); my $id = CUL_HM_Id($iohash);
CUL_HM_infoUpdtDevData($shash->{NAME}, $shash,$p)
if (!$modules{CUL_HM}{helper}{hmManualOper}#no autoaction
||$iohash->{hmPair}
||$iohash->{hmPairSerial} );
if( $dst =~ m /(000000|$id)/ #--- see if we need to pair if( $dst =~ m /(000000|$id)/ #--- see if we need to pair
&&($iohash->{hmPair} &&($iohash->{hmPair}
@ -1848,6 +1850,10 @@ sub CUL_HM_parseCommon(@){#####################################################
} }
sub CUL_HM_queueUpdtCfg($){ sub CUL_HM_queueUpdtCfg($){
my $name = shift; my $name = shift;
if ($modules{CUL_HM}{helper}{hmManualOper}){ # no update when manual operation
delete $modules{CUL_HM}{helper}{updtCfgLst};
return;
}
my @arr; my @arr;
if ($modules{CUL_HM}{helper}{updtCfgLst}){ if ($modules{CUL_HM}{helper}{updtCfgLst}){
@arr = CUL_HM_noDup((@{$modules{CUL_HM}{helper}{updtCfgLst}}, $name)); @arr = CUL_HM_noDup((@{$modules{CUL_HM}{helper}{updtCfgLst}}, $name));
@ -2596,7 +2602,6 @@ sub CUL_HM_Set($@) {
return "entry must be between 1 and 36" if ($eNo < 1 || $eNo > 36); return "entry must be between 1 and 36" if ($eNo < 1 || $eNo > 36);
my $sndID = CUL_HM_name2Id($sId); my $sndID = CUL_HM_name2Id($sId);
my $recID = CUL_HM_name2Id($rId); my $recID = CUL_HM_name2Id($rId);
$sndID = AttrVal($sId,"hmId","");
if ($sndID !~ m/(^[0-9A-F]{6})$/){$sndID = AttrVal($sId,"hmId","");}; if ($sndID !~ m/(^[0-9A-F]{6})$/){$sndID = AttrVal($sId,"hmId","");};
if ($recID !~ m/(^[0-9A-F]{6})$/){$recID = AttrVal($rId,"hmId","");}; if ($recID !~ m/(^[0-9A-F]{6})$/){$recID = AttrVal($rId,"hmId","");};
return "sender ID $sId unknown:".$sndID if ($sndID !~ m/(^[0-9A-F]{6})$/); return "sender ID $sId unknown:".$sndID if ($sndID !~ m/(^[0-9A-F]{6})$/);
@ -3385,12 +3390,12 @@ sub CUL_HM_ProcessCmdStack($) {
return; return;
} }
sub CUL_HM_prtInit ($){ #setup protocol variables after define sub CUL_HM_prtInit($){ #setup protocol variables after define
my ($hash)=@_; my ($hash)=@_;
$hash->{helper}{prt}{sProc} = 0; # stack not being processed by now $hash->{helper}{prt}{sProc} = 0; # stack not being processed by now
$hash->{helper}{prt}{bErr}=0; $hash->{helper}{prt}{bErr}=0;
} }
sub CUL_HM_respWaitSu ($@){ #setup response for multi-message response sub CUL_HM_respWaitSu($@){ #setup response for multi-message response
# single commands # single commands
# cmd: single msg that needs to be ACKed # cmd: single msg that needs to be ACKed
# mNo: number of message (needs to be in ACK) # mNo: number of message (needs to be in ACK)
@ -3533,11 +3538,11 @@ sub CUL_HM_sndIfOpen($) {
my(undef,$io) = split(':',$_[0]); my(undef,$io) = split(':',$_[0]);
RemoveInternalTimer("sndIfOpen:$io");# should not be necessary, but RemoveInternalTimer("sndIfOpen:$io");# should not be necessary, but
my $ioHash = $defs{$io}; my $ioHash = $defs{$io};
if ( $ioHash->{STATE} ne "opened" if ( $ioHash->{STATE} !~ m/^(opened|Initialized)$/
||(defined $ioHash->{XmitOpen} && $ioHash->{XmitOpen} == 0) ||(defined $ioHash->{XmitOpen} && $ioHash->{XmitOpen} == 0)
# ||$modules{CUL_HM}{prot}{rspPend}>=$maxPendCmds # ||$modules{CUL_HM}{prot}{rspPend}>=$maxPendCmds
){#still no send allowed ){#still no send allowed
if ($modules{CUL_HM}{$io}{tmrStart} < gettimeofday() - $IOpolltout){ if ($modules{CUL_HM}{$io}{tmrStart} < gettimeofday() - $modules{CUL_HM}{hmIoMaxDly}){
# we need to clean up - this is way to long Stop delay # we need to clean up - this is way to long Stop delay
if ($modules{CUL_HM}{$io}{pendDev}) { if ($modules{CUL_HM}{$io}{pendDev}) {
while(@{$modules{CUL_HM}{$io}{pendDev}}){ while(@{$modules{CUL_HM}{$io}{pendDev}}){
@ -3570,10 +3575,10 @@ sub CUL_HM_SndCmd($$) {
|| AttrVal($hash->{NAME},"ignore","") || AttrVal($hash->{NAME},"ignore","")
|| AttrVal($hash->{NAME},"dummy","")); || AttrVal($hash->{NAME},"dummy",""));
my $ioName = $io->{NAME}; my $ioName = $io->{NAME};
if ((hex substr($cmd,2,2) & 0x20) && ( # check for commands with resp-req if ( $io->{STATE} !~ m/^(opened|Initialized)$/ # we need to queue
$io->{STATE} !~ m/^(opened|Initialized)$/ # we need to queue ||(hex substr($cmd,2,2) & 0x20) && ( # check for commands with resp-req
|| $modules{CUL_HM}{$ioName}{tmr} # queue already running $modules{CUL_HM}{$ioName}{tmr} # queue already running
||(defined $io->{XmitOpen} && $io->{XmitOpen} == 0)#overload, dont send ||(defined $io->{XmitOpen} && $io->{XmitOpen} == 0)#overload, dont send
) )
){ ){
@ -3582,7 +3587,7 @@ sub CUL_HM_SndCmd($$) {
# repetition will be stopped after 1min forsecurity reason. # repetition will be stopped after 1min forsecurity reason.
my @arr = (); my @arr = ();
$hash->{cmdStack} = \@arr if(!$hash->{cmdStack}); $hash->{cmdStack} = \@arr if(!$hash->{cmdStack});
unshift (@{$hash->{cmdStack}}, $cmd);#pushback cmd, wait for opportunitiy unshift (@{$hash->{cmdStack}}, $cmd);#pushback cmd, wait for opportunity
# push device to list # push device to list
if (!defined $modules{CUL_HM}{$ioName}{tmr}){ if (!defined $modules{CUL_HM}{$ioName}{tmr}){
@ -3596,7 +3601,6 @@ sub CUL_HM_SndCmd($$) {
@{$modules{CUL_HM}{$ioName}{pendDev}} = @{$modules{CUL_HM}{$ioName}{pendDev}} =
CUL_HM_noDup(@{$modules{CUL_HM}{$ioName}{pendDev}},$hash->{NAME}); CUL_HM_noDup(@{$modules{CUL_HM}{$ioName}{pendDev}},$hash->{NAME});
CUL_HM_respPendRm($hash);#rm timer - we are out CUL_HM_respPendRm($hash);#rm timer - we are out
if ($modules{CUL_HM}{$ioName}{tmr} != 1){# need to start timer if ($modules{CUL_HM}{$ioName}{tmr} != 1){# need to start timer
my $tn = gettimeofday(); my $tn = gettimeofday();
InternalTimer($tn+$IOpoll, "CUL_HM_sndIfOpen", "sndIfOpen:$ioName", 0); InternalTimer($tn+$IOpoll, "CUL_HM_sndIfOpen", "sndIfOpen:$ioName", 0);
@ -3633,6 +3637,8 @@ sub CUL_HM_respPendRm($) {#del response related entries in messageing entity
$modules{CUL_HM}{prot}{rspPend}-- if($hash->{helper}{prt}{rspWait}{cmd}); $modules{CUL_HM}{prot}{rspPend}-- if($hash->{helper}{prt}{rspWait}{cmd});
delete ($hash->{helper}{prt}{rspWait}); delete ($hash->{helper}{prt}{rspWait});
delete $hash->{helper}{tmdOn}; delete $hash->{helper}{tmdOn};
delete $hash->{helper}{prt}{mmcA};
delete $hash->{helper}{prt}{mmcS};
RemoveInternalTimer($hash); # remove resend-timer RemoveInternalTimer($hash); # remove resend-timer
RemoveInternalTimer("respPend:$hash->{DEF}");# remove responsePending timer RemoveInternalTimer("respPend:$hash->{DEF}");# remove responsePending timer
$respRemoved = 1; $respRemoved = 1;
@ -3654,26 +3660,17 @@ sub CUL_HM_respPendTout($) {
$pHash->{awake} = 0;# set to asleep $pHash->{awake} = 0;# set to asleep
CUL_HM_protState($hash,"CMDs_pending"); CUL_HM_protState($hash,"CMDs_pending");
} }
elsif ($hash->{IODev}->{STATE} !~ m/^(opened|Initialized)$/){#IO errors
CUL_HM_eventP($hash,"IOdly");
CUL_HM_ProcessCmdStack($hash) if(CUL_HM_getRxType($hash) & 0x03);
}
elsif ($pHash->{rspWait}{reSent} > AttrVal($hash->{NAME},"msgRepeat",3) # too much elsif ($pHash->{rspWait}{reSent} > AttrVal($hash->{NAME},"msgRepeat",3) # too much
||((CUL_HM_getRxType($hash) & 0x83) == 0)){ #to slow ||((CUL_HM_getRxType($hash) & 0x83) == 0)){ #to slow
if ($pHash->{mmcA}){ my $pendCmd = ($pHash->{rspWait}{Pending}
#shall we re-insert commands?
#unshift @{$hash->{cmdStack}},@{$pHash->{mmcA}};
delete $pHash->{mmcA};
delete $pHash->{mmcS};
}
if ($hash->{IODev}->{STATE} !~ m/^(opened|Initialized)$/){#IO errors
CUL_HM_eventP($hash,"IOerr");
readingsSingleUpdate($hash,"state","IOerr",1);
}
else{
my $pendCmd = ($pHash->{rspWait}{Pending}
?"RESPONSE TIMEOUT:".$pHash->{rspWait}{Pending} ?"RESPONSE TIMEOUT:".$pHash->{rspWait}{Pending}
:"MISSING ACK");# save before remove :"MISSING ACK");# save before remove
CUL_HM_eventP($hash,"ResndFail"); CUL_HM_eventP($hash,"ResndFail");
readingsSingleUpdate($hash,"state",$pendCmd,1); readingsSingleUpdate($hash,"state",$pendCmd,1);
}
CUL_HM_ProcessCmdStack($hash); # continue processing commands if any CUL_HM_ProcessCmdStack($hash); # continue processing commands if any
} }
else{# manage retries else{# manage retries
@ -3682,7 +3679,8 @@ sub CUL_HM_respPendTout($) {
$pHash->{rspWait}{reSent}++; $pHash->{rspWait}{reSent}++;
my (undef,$addr,$msg) = unpack 'A10A12A*',$hash->{helper}{prt}{rspWait}{cmd}; my (undef,$addr,$msg) = unpack 'A10A12A*',$hash->{helper}{prt}{rspWait}{cmd};
$pHash->{rspWaitSec}{$_} = $pHash->{rspWait}{$_} foreach (keys%{$pHash->{rspWait}}); ; $pHash->{rspWaitSec}{$_} = $pHash->{rspWait}{$_}
foreach (keys%{$pHash->{rspWait}});
CUL_HM_SndCmd($hash,"++B112$addr"); CUL_HM_SndCmd($hash,"++B112$addr");
$hash->{helper}{prt}{awake}=4;# start re-wakeup $hash->{helper}{prt}{awake}=4;# start re-wakeup
} }
@ -3717,16 +3715,24 @@ sub CUL_HM_eventP($$) {#handle protocol events
$nAttr->{"prot".$evntType} = ++$evntCnt." last_at:".TimeNow(); $nAttr->{"prot".$evntType} = ++$evntCnt." last_at:".TimeNow();
if ($evntType =~ m/(Nack|ResndFail|IOerr)/){# unrecoverable Error if ($evntType =~ m/(Nack|ResndFail|IOerr)/){# unrecoverable Error
readingsSingleUpdate($hash,"state",$evntType,1);
$hash->{helper}{prt}{bErr}++; $hash->{helper}{prt}{bErr}++;
$nAttr->{protCmdDel}++; $nAttr->{protCmdDel} = 0 if(!$nAttr->{protCmdDel});
if ( (CUL_HM_getRxType($hash) & 0x01) == 0 #to slow for wakeup and config $nAttr->{protCmdDel} += scalar @{$hash->{cmdStack}} + 1
#no retry for burst either
|| $evntType eq "IOerr"){ #IO problem
$nAttr->{protCmdDel} = 0 if(!$nAttr->{protCmdDel});
$nAttr->{protCmdDel} += scalar @{$hash->{cmdStack}}
if ($hash->{cmdStack}); if ($hash->{cmdStack});
CUL_HM_protState($hash,"CMDs_done".($hash->{helper}{prt}{bErr}? CUL_HM_protState($hash,"CMDs_done".($hash->{helper}{prt}{bErr}?
("_Errors:".$hash->{helper}{prt}{bErr}):"")); ("_Errors:".$hash->{helper}{prt}{bErr}):""));
CUL_HM_respPendRm($hash);
}
elsif($evntType eq "IOdly"){ # IO problem - will see whether it recovers
my $pHash = $hash->{helper}{prt};
if ($pHash->{mmcA}){
unshift @{$hash->{cmdStack}},$_ foreach (reverse@{$pHash->{mmcA}});
delete $pHash->{mmcA};
delete $pHash->{mmcS};
}
else{
unshift @{$hash->{cmdStack}}, $pHash->{rspWait}{cmd};#pushback
} }
CUL_HM_respPendRm($hash); CUL_HM_respPendRm($hash);
} }
@ -4804,6 +4810,7 @@ sub CUL_HM_unQEntity($$){# remove entity from q - task no longer necesary
} }
sub CUL_HM_qEntity($$){ sub CUL_HM_qEntity($$){
my ($name,$q) = @_; my ($name,$q) = @_;
return if ($modules{CUL_HM}{helper}{hmManualOper});#no autoaction when manual
$q = $modules{CUL_HM}{helper}{$q}; $q = $modules{CUL_HM}{helper}{$q};
return if (AttrVal($name,"subType","") eq "virtual"); return if (AttrVal($name,"subType","") eq "virtual");
if ($defs{$name}{helper}{role}{dev}){ if ($defs{$name}{helper}{role}{dev}){

View File

@ -23,11 +23,12 @@ sub HMinfo_Initialize($$) {####################################################
$hash->{DefFn} = "HMinfo_Define"; $hash->{DefFn} = "HMinfo_Define";
$hash->{SetFn} = "HMinfo_SetFn"; $hash->{SetFn} = "HMinfo_SetFn";
$hash->{AttrFn} = "HMinfo_Attr"; $hash->{AttrFn} = "HMinfo_Attr";
$hash->{AttrList} = "loglevel:0,1,2,3,4,5,6 ". $hash->{AttrList} = "loglevel:0,1,2,3,4,5,6 "
"sumStatus sumERROR ". ."sumStatus sumERROR "
"autoUpdate ". ."autoUpdate "
"hmAutoReadScan ". ."hmAutoReadScan hmIoMaxDly "
$readingFnAttributes; ."hmManualOper:0_auto,1_manual "
.$readingFnAttributes;
} }
sub HMinfo_Define($$){######################################################### sub HMinfo_Define($$){#########################################################
@ -69,7 +70,7 @@ sub HMinfo_Attr(@) {#################################
$hash->{helper}{autoUpdate} = $sec; $hash->{helper}{autoUpdate} = $sec;
InternalTimer(gettimeofday()+$sec,"HMinfo_autoUpdate","sUpdt:".$name,0); InternalTimer(gettimeofday()+$sec,"HMinfo_autoUpdate","sUpdt:".$name,0);
} }
elsif ($attrName eq "hmAutoReadScan"){# 00:00 hh:mm elsif($attrName eq "hmAutoReadScan"){# 00:00 hh:mm
if ($cmd eq "del"){ if ($cmd eq "del"){
$modules{CUL_HM}{hmAutoReadScan} = 4;# return to default $modules{CUL_HM}{hmAutoReadScan} = 4;# return to default
} }
@ -83,6 +84,29 @@ sub HMinfo_Attr(@) {#################################
CUL_HM_queueAutoRead(""); #will restart timer CUL_HM_queueAutoRead(""); #will restart timer
} }
} }
elsif($attrName eq "hmIoMaxDly"){#
if ($cmd eq "del"){
$modules{CUL_HM}{hmIoMaxDly} = 60;# return to default
}
else{
return "please add plain integer between 0 and 3600"
if ( $attrVal !~ m/^(\d+)$/
||$attrVal<0
||$attrVal >3600 );
## implement new timer to CUL_HM
$modules{CUL_HM}{hmIoMaxDly}=$attrVal;
}
}
elsif($attrName eq "hmManualOper"){# 00:00 hh:mm
if ($cmd eq "del"){
$modules{CUL_HM}{helper}{hmManualOper} = 0;# default automode
}
else{
return "please set 0 or 1" if ($attrVal !~ m/^(0|1)/);
## implement new timer to CUL_HM
$modules{CUL_HM}{helper}{hmManualOper} = substr($attrVal,0,1);
}
}
return; return;
} }
sub HMinfo_autoUpdate($){#in:name, send status-request sub HMinfo_autoUpdate($){#in:name, send status-request
@ -1359,6 +1383,18 @@ sub HMinfo_noDup(@) {#return list with no duplicates
Note that compressing will increase message load while stretch will extent waiting time. Note that compressing will increase message load while stretch will extent waiting time.
data. <br> data. <br>
</li> </li>
<li><a name="#HMhmIoMaxDly">hmIoMaxDly</a>
max time in seconds CUL_HM stacks messages if the IO device is not ready to send.
If the IO device will not reappear in time all command will be deleted and IOErr will be reported.<br>
Note: commands will be executed after the IO device reappears - which could lead to unexpected
activity long after command issue.<br>
default is 60sec. max value is 3600sec<br>
</li>
<li><a name="#HMhmManualOper">hmManualOper</a>
set to 1 will prevent any automatic operation, update or default settings
in CUL_HM.<br>
</li>
</ul> </ul>
<br> <br>
<a name="HMinfovariables"><b>Variables</b></a> <a name="HMinfovariables"><b>Variables</b></a>

View File

@ -1342,8 +1342,8 @@ my %culHmBits = (
BUTTON => '00,2,$val=(hex($val)&0x3F)', BUTTON => '00,2,$val=(hex($val)&0x3F)',
LONG => '00,2,$val=(hex($val)&0x40)?1:0', LONG => '00,2,$val=(hex($val)&0x40)?1:0',
LOWBAT => '00,2,$val=(hex($val)&0x80)?1:0', LOWBAT => '00,2,$val=(hex($val)&0x80)?1:0',
VALUE => '02,2,$val=(hex($val))', NBR => '02,2,$val=(hex($val))',
NEXT => '04,2,$val=(hex($val))',} }, VALUE => '04,2,$val=(hex($val))',} },
"53" => { txt => "SensorData" , params => { "53" => { txt => "SensorData" , params => {
CMD => "00,2", CMD => "00,2",
Fld1=> "02,2", Fld1=> "02,2",