10_ZWave.pm/00_ZWDongle.pm: fix ACK-code to work with the unfinished secureInit

git-svn-id: svn://svn.code.sf.net/p/fhem/code/trunk@8744 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
rudolfkoenig
2015-06-14 12:53:44 +00:00
parent 49dffa9f9d
commit 665f39bd81
2 changed files with 66 additions and 62 deletions

View File

@@ -228,11 +228,9 @@ ZWDongle_Define($$)
$hash->{DeviceName} = $dev; $hash->{DeviceName} = $dev;
$hash->{CallbackNr} = 0; $hash->{CallbackNr} = 0;
$hash->{nrNAck} = 0; $hash->{nrNAck} = 0;
$hash->{WaitForAck}=0;
$hash->{SendRetrys}=0;
$hash->{MaxSendRetrys}=3;
my @empty; my @empty;
$hash->{SendStack} = \@empty; $hash->{SendStack} = \@empty;
ZWDongle_shiftSendStack($hash, 5, undef);
my $ret = DevIo_OpenDev($hash, 0, "ZWDongle_DoInit"); my $ret = DevIo_OpenDev($hash, 0, "ZWDongle_DoInit");
return $ret; return $ret;
@@ -264,6 +262,7 @@ ZWDongle_Set($@)
return "Unknown argument $type, choose one of " . join(" ",@r); return "Unknown argument $type, choose one of " . join(" ",@r);
} }
Log3 $hash, 4, "ZWDongle set $name $type ".join(" ",@a);
if($type eq "reopen") { if($type eq "reopen") {
return if(AttrVal($name, "dummy",undef) || AttrVal($name, "disable",undef)); return if(AttrVal($name, "dummy",undef) || AttrVal($name, "disable",undef));
DevIo_CloseDev($hash); DevIo_CloseDev($hash);
@@ -295,12 +294,11 @@ ZWDongle_Set($@)
} }
if($type eq "addNode") { if($type eq "addNode") {
if(@a == 2 && $a[2] =~ m/^sec/i) { if(@a == 2 && $a[1] =~ m/^sec/i) {
$hash->{addSecure} = pop(@a); $hash->{addSecure} = pop(@a);
} else { } else {
delete($hash->{addSecure}); delete($hash->{addSecure});
} }
Log 1, "CMD:".join("/",@a)."/";
} }
my @ca = split("%", $cmd, -1); my @ca = split("%", $cmd, -1);
@@ -332,6 +330,7 @@ ZWDongle_Get($@)
return "$type is unsupported by this controller"; return "$type is unsupported by this controller";
} }
Log3 $hash, 4, "ZWDongle get $name $type ".join(" ",@a);
my @ga = split("%", $gets{$type}, -1); my @ga = split("%", $gets{$type}, -1);
my $nargs = int(@ga)-1; my $nargs = int(@ga)-1;
return "get $name $type needs $nargs arguments" if($nargs != int(@a)); return "get $name $type needs $nargs arguments" if($nargs != int(@a));
@@ -474,9 +473,9 @@ ZWDongle_DoInit($)
ZWDongle_Get($hash, $name, "homeId"); ZWDongle_Get($hash, $name, "homeId");
ZWDongle_Get($hash, $name, ("random", 32)); # Sec relevant ZWDongle_Get($hash, $name, ("random", 32)); # Sec relevant
ZWDongle_Set($hash, $name, ("timeouts", 100, 15)); # Sec relevant ZWDongle_Set($hash, $name, ("timeouts", 100, 15)); # Sec relevant
ZWDongle_ReadAnswer($hash, "timeouts", "^0106");
# NODEINFO_LISTENING, Generic Static controller, Specific Static Controller, 0 # NODEINFO_LISTENING, Generic Static controller, Specific Static Controller, 0
ZWDongle_Set($hash, $name, ("setNIF", 1, 2, 1, 0)); # Sec relevant (?) ZWDongle_Set($hash, $name, ("setNIF", 1, 2, 1, 0)); # Sec relevant (?)
ZWDongle_Clear($hash); # Wait, timeouts needs ack
$hash->{STATE} = "Initialized"; $hash->{STATE} = "Initialized";
return undef; return undef;
} }
@@ -498,11 +497,16 @@ ZWDongle_Write($$$)
{ {
my ($hash,$fn,$msg) = @_; my ($hash,$fn,$msg) = @_;
Log3 $hash, 5, "ZWDongle_Write msg $msg"; if($fn !~ m/^[0-9A-F]+$/i) { # ACK initiated from ZWDongle
ZWDongle_shiftSendStack($hash, 5, $fn);
return;
}
Log3 $hash, 5, "ZWDongle_Write $fn $msg";
# assemble complete message # assemble complete message
$msg = "$fn$msg"; $msg = "$fn$msg";
$msg = sprintf("%02x%s", length($msg)/2+1, $msg); $msg = sprintf("%02x%s", length($msg)/2+1, $msg);
$msg = "01$msg" . ZWDongle_CheckSum($msg); $msg = "01$msg" . ZWDongle_CheckSum($msg);
# push message on stack # push message on stack
@@ -523,53 +527,59 @@ ZWDongle_Write($$$)
unshift($hash->{SendStack}, $w1) if($w1); unshift($hash->{SendStack}, $w1) if($w1);
} }
#send first message if not waiting for ACK
ZWave_ProcessSendStack($hash); ZWave_ProcessSendStack($hash);
} }
sub
ZWDongle_shiftSendStack($$$)
{
my ($hash, $level, $txt) = @_;
my $ss = $hash->{SendStack};
my $cmd = shift @{$ss};
Log3 $hash, $level, "$txt, removing $cmd from sendstack" if($txt && $cmd);
$hash->{WaitForAck}=0;
$hash->{SendRetries}=0;
$hash->{MaxSendRetries}=3;
}
sub sub
ZWave_ProcessSendStack($) ZWave_ProcessSendStack($)
{ {
my ($hash) = @_; my ($hash) = @_;
Log3 $hash, 5, "ZWave_ProcessSendStack: ".@{$hash->{SendStack}}. #Log3 $hash, 1, "ZWave_ProcessSendStack: ".@{$hash->{SendStack}}.
" items on stack, waitForAck ".$hash->{WaitForAck}; # " items on stack, waitForAck ".$hash->{WaitForAck};
RemoveInternalTimer($hash); RemoveInternalTimer($hash);
my $ts = gettimeofday(); my $ts = gettimeofday();
if($hash->{WaitForAck}){ if($hash->{WaitForAck}){
if($ts-$hash->{SendTime} > 1){ if($ts-$hash->{SendTime} >= 1){
Log3 $hash, 2, Log3 $hash, 2, "ZWave_ProcessSendStack: no ACK, resending message";
"ZWave_ProcessSendStack: timeout sending message -> trigger resend"; $hash->{SendRetries}++;
$hash->{SendRetrys}++;
$hash->{WaitForAck} = 0; $hash->{WaitForAck} = 0;
} else { } else {
Log3 $hash, 5, "ZWave_ProcessSendStack: waiting for ACK -> check again";
InternalTimer($ts+1, "ZWave_ProcessSendStack", $hash, 0); InternalTimer($ts+1, "ZWave_ProcessSendStack", $hash, 0);
return; return;
} }
} }
if($hash->{SendRetrys} > $hash->{MaxSendRetrys}){ if($hash->{SendRetries} > $hash->{MaxSendRetries}){
Log3 $hash, 1, ZWDongle_shiftSendStack($hash, 1, "ERROR: max send retries reached");
"ZWave_ProcessSendStack: max send retrys reached -> cancel sending";
shift @{$hash->{SendStack}};
$hash->{WaitForAck} = 0;
$hash->{SendRetrys} = 0;
$hash->{MaxSendRetrys} = 3;
} }
return if(!@{$hash->{SendStack}} || $hash->{WaitForAck}); return if(!@{$hash->{SendStack}} || $hash->{WaitForAck});
my $msg = $hash->{SendStack}->[0]; my $msg = $hash->{SendStack}->[0];
Log3 $hash, 5, "ZWave_ProcessSendStack: sending msg ".$msg;
DevIo_SimpleWrite($hash, $msg, 1); DevIo_SimpleWrite($hash, $msg, 1);
$hash->{WaitForAck} = 1; $hash->{WaitForAck} = 1;
$hash->{SendTime} = $ts; $hash->{SendTime} = $ts;
InternalTimer($ts+1, "ZWave_ProcessSendStack", $hash, 0); InternalTimer($ts+1, "ZWave_ProcessSendStack", $hash, 0);
} }
@@ -594,38 +604,39 @@ ZWDongle_Read($@)
$hash->{ReadTime} = $ts; $hash->{ReadTime} = $ts;
Log3 $name, 5, "ZWDongle RAW buffer: $data"; #Log3 $name, 5, "ZWDongle RAW buffer: $data";
my $msg; my $msg;
while(length($data) > 0) { while(length($data) > 0) {
my $fb = substr($data, 0, 2); my $fb = substr($data, 0, 2);
if($fb eq "06") { # ACK if($fb eq "06") { # ACK
Log3 $name, 5, "$name: ACK received"; # ZWDongle messages are removed upon first ACK.
$data = substr($data, 2); # Other network messages are removed if ZW_SEND_DATA:OK is received
# ZWDongle messages are removed if ZW_SEND_DATA:OK is received my $sst = $hash->{SendStack}->[0];
if(!@{$hash->{SendStack}} || $hash->{SendStack}->[0] !~ m/^01....13/) { if($sst && $sst !~ m/^01....13/) {
shift @{$hash->{SendStack}}; ZWDongle_shiftSendStack($hash, 5, "ACK received");
$hash->{WaitForAck} = 0;
$hash->{SendRetrys} = 0;
$hash->{MaxSendRetrys} = 3;
} }
$data = substr($data, 2);
next; next;
} }
if($fb eq "15") { # NACK if($fb eq "15") { # NACK
Log3 $name, 4, "$name: NACK received, resending the message"; Log3 $name, 4, "ZWDongle_Read $name: NACK received";
$hash->{WaitForAck} = 0; $hash->{WaitForAck} = 0;
$hash->{SendRetrys}++; $hash->{SendRetries}++;
$data = substr($data, 2); $data = substr($data, 2);
next; next;
} }
if($fb eq "18") { # CAN if($fb eq "18") { # CAN
Log3 $name, 4, "$name: CAN received, resending the message"; Log3 $name, 4, "ZWDongle_Read $name: CAN received";
$hash->{WaitForAck} = 0; $hash->{WaitForAck} = 0;
$hash->{SendRetrys}++; $hash->{SendRetries}++;
$hash->{MaxSendRetrys}++ if($hash->{MaxSendRetrys}<7); $hash->{MaxSendRetries}++ if($hash->{MaxSendRetries}<7);
$data = substr($data, 2); $data = substr($data, 2);
next; next;
} }
@@ -661,17 +672,12 @@ ZWDongle_Read($@)
next; next;
} }
$hash->{nrNAck} = 0; $hash->{nrNAck} = 0;
Log3 $name, 5, "ZWDongle_Read $name: ACK, processing $msg"; Log3 $name, 4, "ZWDongle_Read $name: sending ACK, processing $msg";
DevIo_SimpleWrite($hash, "06", 1); # Send ACK DevIo_SimpleWrite($hash, "06", 1); # Send ACK
# SEND_DATA OK: remove message from SendStack. TODO: check the callbackId # SEND_DATA OK: remove message from SendStack. TODO: check the callbackId
if($msg =~ m/^0013..00/ ){ if($msg =~ m/^0013..00/ ){
Log3 $name, 5, ZWDongle_shiftSendStack($hash, 5, "ZW_SEND_DATA:OK received");
"ZWDongle_Read $name: ZW_SEND_DATA:OK received -> removing message";
shift @{$hash->{SendStack}};
$hash->{WaitForAck} = 0;
$hash->{SendRetrys} = 0;
$hash->{MaxSendRetrys} = 3;
} }
last if(defined($local) && (!defined($regexp) || ($msg =~ m/$regexp/))); last if(defined($local) && (!defined($regexp) || ($msg =~ m/$regexp/)));
@@ -687,11 +693,7 @@ ZWDongle_Read($@)
# trigger sending of next message # trigger sending of next message
ZWave_ProcessSendStack($hash) if(length($data) == 0); ZWave_ProcessSendStack($hash) if(length($data) == 0);
if(defined($local)){ return $msg if(defined($local));
Log3 $name, 5, "ZWDongle_Read returning local msg ".
($msg ? $msg:"undef")." hash PARTIAL: ".$hash->{PARTIAL};
return $msg;
}
return undef; return undef;
} }
@@ -743,12 +745,11 @@ ZWDongle_ReadAnswer($$$)
Log3 $hash, 1,"ZWDongle_ReadAnswer: no data read"; Log3 $hash, 1,"ZWDongle_ReadAnswer: no data read";
return ("No data", undef); return ("No data", undef);
} }
Log3 $hash, 5, "ZWDongle_ReadAnswer: read ".length($buf)." bytes";
} }
my $ret = ZWDongle_Read($hash, $buf, $regexp); my $ret = ZWDongle_Read($hash, $buf, $regexp);
if(defined($ret)){ if(defined($ret)){
Log3 $hash, 5, "ZWDongle_ReadAnswer: returning $ret"; Log3 $hash, 4, "ZWDongle_ReadAnswer for $arg: $ret";
return (undef, $ret); return (undef, $ret);
} }
} }
@@ -760,7 +761,7 @@ ZWDongle_Parse($$$)
my ($hash, $name, $rmsg) = @_; my ($hash, $name, $rmsg) = @_;
if(!defined($hash->{STATE}) || $hash->{STATE} ne "Initialized"){ if(!defined($hash->{STATE}) || $hash->{STATE} ne "Initialized"){
Log3 $hash, 4,"ZWDongle_Parse dongle not initialized"; Log3 $hash, 4,"ZWDongle_Parse $rmsg: dongle not yet initialized";
return; return;
} }

View File

@@ -350,8 +350,8 @@ my %zwave_class = (
"secNonce" => "40" }, "secNonce" => "40" },
get => { "secSupported" => "02" }, get => { "secSupported" => "02" },
parse => { "..9803(.*)" => '"secSupported:$1"', parse => { "..9803(.*)" => '"secSupported:$1"',
"..9805(.*)" => 'ZWave_securityInit($hash, $1)', "..9805(.*)" => 'ZWave_secureInit($hash, $1)', # secScheme
"..9880(.*)" => 'ZWave_securityInit($hash, $1)' } }, "..9880(.*)" => 'ZWave_secureInit($hash, $1)' } },
AV_TAGGING_MD => { id => '99' }, AV_TAGGING_MD => { id => '99' },
IP_CONFIGURATION => { id => '9a' }, IP_CONFIGURATION => { id => '9a' },
ASSOCIATION_COMMAND_CONFIGURATION ASSOCIATION_COMMAND_CONFIGURATION
@@ -380,7 +380,6 @@ my %zwave_cmdArgs = (
my %zwave_modelConfig; my %zwave_modelConfig;
my %zwave_modelIdAlias = ( "010f-0301-1001" => "Fibaro_FGRM222", my %zwave_modelIdAlias = ( "010f-0301-1001" => "Fibaro_FGRM222",
"013c-0001-0003" => "Philio_PAN04",
"0115-0100-0102" => "ZME_KFOB" ); "0115-0100-0102" => "ZME_KFOB" );
# Patching certain devices. # Patching certain devices.
@@ -1454,7 +1453,7 @@ ZWave_sensorbinaryV2Parse($$)
} }
sub sub
ZWave_securityInit(@) ZWave_secureInit(@)
{ {
my ($hash, $param) = @_; my ($hash, $param) = @_;
my $iodev = $hash->{IODev}; my $iodev = $hash->{IODev};
@@ -1463,7 +1462,10 @@ ZWave_securityInit(@)
$hash->{secStatus} = 0 if(!$hash->{secStatus}); $hash->{secStatus} = 0 if(!$hash->{secStatus});
my $status = ++$hash->{secStatus}; my $status = ++$hash->{secStatus};
Log3 $iodev, 4, "$hash->{NAME}: securityInit status $status"; my @stTxt = ( "secScheme", "secKey", "secNonce", "done");
my $stTxt = ($status > int(@stTxt) ? "ERR" : $stTxt[$status-1]);
Log3 $iodev, 4, "*** $hash->{NAME}: secureInit status $status/$stTxt";
if($status == 1) { if($status == 1) {
ZWave_Set($hash, $name, "secScheme"); ZWave_Set($hash, $name, "secScheme");
return ""; # not evaluated return ""; # not evaluated
@@ -1475,10 +1477,11 @@ ZWave_securityInit(@)
return undef; # No Event/Reading return undef; # No Event/Reading
} elsif($status == 3) { } elsif($status == 3) {
IOWrite($hash, "secKey ACK", "");
ZWave_Set($hash, $name, "secNonce"); ZWave_Set($hash, $name, "secNonce");
return undef; # No Event/Reading return undef; # No Event/Reading
} else { } elsif($status == 4) {
Log3 $iodev, 4, "secNonce report: $param"; Log3 $iodev, 4, "secNonce report: $param";
delete $iodev->{secInitName}; delete $iodev->{secInitName};
delete $hash->{secStatus}; delete $hash->{secStatus};
@@ -1544,7 +1547,7 @@ ZWave_Parse($$@)
if($cmd eq "ZW_SEND_DATA") { if($cmd eq "ZW_SEND_DATA") {
Log3 $ioName, 2, "ERROR: cannot SEND_DATA: $arg" if($arg != 1); Log3 $ioName, 2, "ERROR: cannot SEND_DATA: $arg" if($arg != 1);
my $si = $iodev->{secInitName}; my $si = $iodev->{secInitName};
ZWave_securityInit($defs{$si}) # No extra response for set networkKey ZWave_secureInit($defs{$si}) # No extra response for set networkKey
if($si && $defs{$si} && $defs{$si}{secStatus} && if($si && $defs{$si} && $defs{$si}{secStatus} &&
$defs{$si}{secStatus} == 2); $defs{$si}{secStatus} == 2);
return ""; return "";
@@ -1595,7 +1598,7 @@ ZWave_Parse($$@)
my $key = AttrVal($ioName, "networkKey", ""); my $key = AttrVal($ioName, "networkKey", "");
if($key) { if($key) {
$iodev->{secInitName} = $dh->{NAME}; $iodev->{secInitName} = $dh->{NAME};
return ZWave_securityInit($dh); return ZWave_secureInit($dh);
} else { } else {
Log3 $ioName, 2, "No secure inclusion as $ioName has no networkKey"; Log3 $ioName, 2, "No secure inclusion as $ioName has no networkKey";
} }
@@ -1757,8 +1760,8 @@ ZWave_Parse($$@)
@{$baseHash->{WakeUp}}=(); @{$baseHash->{WakeUp}}=();
#send a final wakeupNoMoreInformation #send a final wakeupNoMoreInformation
my $nodeId = $baseHash->{id}; my $nodeId = $baseHash->{id};
IOWrite($hash, "00", "13${nodeId}02840805");
Log3 $hash, 4, "Sending wakeupNoMoreInformation to node: $nodeId"; Log3 $hash, 4, "Sending wakeupNoMoreInformation to node: $nodeId";
IOWrite($hash, "00", "13${nodeId}02840805");
} }
$baseHash->{lastMsgTimestamp} = time(); $baseHash->{lastMsgTimestamp} = time();