2
0
mirror of https://github.com/fhem/fhem-mirror.git synced 2025-04-16 04:36:02 +00:00

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

git-svn-id: https://svn.fhem.de/fhem/trunk@8744 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
rudolfkoenig 2015-06-14 12:53:44 +00:00
parent e90c4419c3
commit a44866ec6f
2 changed files with 66 additions and 62 deletions

View File

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

View File

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