mirror of
https://github.com/fhem/fhem-mirror.git
synced 2025-02-08 05:15:10 +00:00
CUL_MAX: implement send queue
git-svn-id: https://svn.fhem.de/fhem/trunk@2701 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
parent
bc449700ce
commit
6ea2c6d835
@ -13,7 +13,7 @@ sub CUL_MAX_Set($@);
|
|||||||
sub CUL_MAX_SendAck($$$);
|
sub CUL_MAX_SendAck($$$);
|
||||||
sub CUL_MAX_SendTimeInformation(@);
|
sub CUL_MAX_SendTimeInformation(@);
|
||||||
sub CUL_MAX_Send(@);
|
sub CUL_MAX_Send(@);
|
||||||
|
sub CUL_MAX_SendQueueHandler($);
|
||||||
my $pairmodeDuration = 60; #seconds
|
my $pairmodeDuration = 60; #seconds
|
||||||
|
|
||||||
my $timeBroadcastInterval = 6*60*60; #= 6 hours, the same time that the cube uses
|
my $timeBroadcastInterval = 6*60*60; #= 6 hours, the same time that the cube uses
|
||||||
@ -62,7 +62,7 @@ CUL_MAX_Define($$)
|
|||||||
$hash->{cnt} = 0;
|
$hash->{cnt} = 0;
|
||||||
$hash->{pairmode} = 0;
|
$hash->{pairmode} = 0;
|
||||||
$hash->{retryCount} = 0;
|
$hash->{retryCount} = 0;
|
||||||
$hash->{devices} = ();
|
$hash->{sendQueue} = [];
|
||||||
AssignIoPort($hash);
|
AssignIoPort($hash);
|
||||||
|
|
||||||
if(CUL_MAX_Check($hash)) {
|
if(CUL_MAX_Check($hash)) {
|
||||||
@ -137,9 +137,6 @@ CUL_MAX_Set($@)
|
|||||||
return undef;
|
return undef;
|
||||||
}
|
}
|
||||||
|
|
||||||
#Array of all packet that we wait to be ack'ed
|
|
||||||
my @waitForAck = ();
|
|
||||||
|
|
||||||
sub
|
sub
|
||||||
CUL_MAX_Parse($$)
|
CUL_MAX_Parse($$)
|
||||||
{
|
{
|
||||||
@ -177,17 +174,13 @@ CUL_MAX_Parse($$)
|
|||||||
Dispatch($shash, "MAX,$isToMe,Ack,$src,$payload", {RAWMSG => $rmsg});
|
Dispatch($shash, "MAX,$isToMe,Ack,$src,$payload", {RAWMSG => $rmsg});
|
||||||
|
|
||||||
return $shash->{NAME} if(!$isToMe);
|
return $shash->{NAME} if(!$isToMe);
|
||||||
|
return $shash->{NAME} if(!@{$shash->{sendQueue}}); #we are not waiting for any Ack
|
||||||
|
|
||||||
my $i = 0;
|
my $packet = $shash->{sendQueue}[0];
|
||||||
while ($i < @waitForAck) {
|
|
||||||
my $packet = $waitForAck[$i];
|
|
||||||
if($packet->{dest} eq $src and $packet->{cnt} == hex($msgcnt)) {
|
if($packet->{dest} eq $src and $packet->{cnt} == hex($msgcnt)) {
|
||||||
Log 5, "Got matching ack";
|
Log 5, "Got matching ack";
|
||||||
splice @waitForAck, $i, 1;
|
$packet->{sent} = 2;
|
||||||
return $shash->{NAME};
|
return $shash->{NAME};
|
||||||
} else {
|
|
||||||
$i++;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} elsif($msgType eq "TimeInformation") {
|
} elsif($msgType eq "TimeInformation") {
|
||||||
@ -279,19 +272,18 @@ CUL_MAX_Send(@)
|
|||||||
#prefix length in bytes
|
#prefix length in bytes
|
||||||
$packet = sprintf("%02x",length($packet)/2) . $packet;
|
$packet = sprintf("%02x",length($packet)/2) . $packet;
|
||||||
|
|
||||||
#Send to CUL
|
Log 5, "CUL_MAX_Send: enqueuing $packet";
|
||||||
IOWrite($hash, "", "Zs". $packet);
|
|
||||||
|
|
||||||
#Schedule checking for Ack
|
|
||||||
return undef if($cmd eq "Ack"); #we don't get an Ack for an Ack
|
|
||||||
return undef if($src ne $hash->{addr}); #we don't handle Ack's for fake messages
|
|
||||||
my $timeout = gettimeofday()+$ackTimeout;
|
my $timeout = gettimeofday()+$ackTimeout;
|
||||||
$waitForAck[@waitForAck] = { "packet" => $packet,
|
my $aref = $hash->{sendQueue};
|
||||||
|
push(@{$aref}, { "packet" => $packet,
|
||||||
"dest" => $dst,
|
"dest" => $dst,
|
||||||
"cnt" => hex($msgcnt),
|
"cnt" => hex($msgcnt),
|
||||||
"time" => $timeout,
|
"time" => $timeout,
|
||||||
"resends" => "0" };
|
"sent" => "0" });
|
||||||
InternalTimer($timeout, "CUL_MAX_Resend", $hash, 0);
|
|
||||||
|
#Call CUL_MAX_SendQueueHandler if we just enqueued the only packet
|
||||||
|
#otherwise it is already in the InternalTimer list
|
||||||
|
CUL_MAX_SendQueueHandler($hash) if(@{$hash->{sendQueue}} == 1);
|
||||||
return undef;
|
return undef;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -302,35 +294,37 @@ CUL_MAX_DeviceHash($)
|
|||||||
return $modules{MAX}{defptr}{$addr};
|
return $modules{MAX}{defptr}{$addr};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#This can be called for two reasons:
|
||||||
|
#1. @sendQueue was empty, CUL_MAX_Send added a packet and then called us
|
||||||
|
#2. We sent a packet from @sendQueue and know the ackTimeout is over.
|
||||||
|
# The packet my still be in @sendQueue (timed out) or removed when the Ack was received.
|
||||||
sub
|
sub
|
||||||
CUL_MAX_Resend($)
|
CUL_MAX_SendQueueHandler($)
|
||||||
{
|
{
|
||||||
my $hash = shift;
|
my $hash = shift;
|
||||||
|
Log 5, "CUL_MAX_SendQueueHandler: " . @{$hash->{sendQueue}} . " items in queue";
|
||||||
|
return if(!@{$hash->{sendQueue}}); #nothing to do
|
||||||
|
|
||||||
my $resendTime = gettimeofday()+60; #some large time
|
my $timeout = gettimeofday(); #reschedule immediatly
|
||||||
my $i = 0;
|
my $packet = $hash->{sendQueue}[0];
|
||||||
while ($i < @waitForAck ) {
|
|
||||||
my $packet = $waitForAck[$i];
|
if( $packet->{sent} == 0 ) { #Need to send it first
|
||||||
if( $packet->{time} <= gettimeofday() ) {
|
#Send to CUL
|
||||||
Log 2, "CUL_MAX_Resend: Missing ack from $packet->{dest} for $packet->{packet}";
|
|
||||||
if($packet->{resends}++ < $resendRetries) {
|
|
||||||
#First resend is one second after original send, second resend it two seconds after first resend, etc
|
|
||||||
$packet->{time} = gettimeofday()+$ackTimeout;
|
|
||||||
IOWrite($hash, "", "Zs". $packet->{packet});
|
IOWrite($hash, "", "Zs". $packet->{packet});
|
||||||
readingsSingleUpdate($hash, "retryCount", ReadingsVal($hash->{NAME}, "retryCount", 0) + 1, 1);
|
$packet->{sent} = 1;
|
||||||
} else {
|
$timeout += $ackTimeout; #reschedule after ackTimeout
|
||||||
Log 1, "CUL_MAX_Resend: Giving up on that packet";
|
|
||||||
splice @waitForAck, $i, 1; #Remove from array
|
} elsif( $packet->{sent} == 1) { #Already sent it, got no Ack
|
||||||
|
Log 2, "CUL_MAX_Resend: Missing ack from $packet->{dest} for $packet->{packet}";
|
||||||
|
splice @{$hash->{sendQueue}}, 0, 1; #Remove from array
|
||||||
readingsSingleUpdate($hash, "packetsLost", ReadingsVal($hash->{NAME}, "packetsLost", 0) + 1, 1);
|
readingsSingleUpdate($hash, "packetsLost", ReadingsVal($hash->{NAME}, "packetsLost", 0) + 1, 1);
|
||||||
next
|
|
||||||
}
|
} elsif( $packet->{sent} == 2) { #Got ack
|
||||||
}
|
splice @{$hash->{sendQueue}}, 0, 1; #Remove from array
|
||||||
$resendTime = $packet->{time} if($packet->{time} < $resendTime);
|
|
||||||
$i++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return if(!@waitForAck); #no need to recheck
|
return if(!@{$hash->{sendQueue}}); #everything done
|
||||||
InternalTimer($resendTime, "CUL_MAX_Resend", $hash, 0);
|
InternalTimer($timeout, "CUL_MAX_SendQueueHandler", $hash, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
sub
|
sub
|
||||||
@ -352,31 +346,25 @@ CUL_MAX_SendTimeInformation(@)
|
|||||||
CUL_MAX_Send($hash, "TimeInformation", $addr, $payload, "04");
|
CUL_MAX_Send($hash, "TimeInformation", $addr, $payload, "04");
|
||||||
}
|
}
|
||||||
|
|
||||||
sub
|
|
||||||
CUL_MAX_SendTimeInformationSender($)
|
|
||||||
{
|
|
||||||
my $args = shift;
|
|
||||||
my ($hash,$addr,$payload) = @{$args};
|
|
||||||
CUL_MAX_SendTimeInformation($hash, $addr, $payload);
|
|
||||||
}
|
|
||||||
|
|
||||||
sub
|
sub
|
||||||
CUL_MAX_BroadcastTime(@)
|
CUL_MAX_BroadcastTime(@)
|
||||||
{
|
{
|
||||||
my ($hash,$manual) = @_;
|
my ($hash,$manual) = @_;
|
||||||
my $payload = CUL_MAX_GetTimeInformationPayload();
|
my $payload = CUL_MAX_GetTimeInformationPayload();
|
||||||
Log 5, "CUL_MAX_BroadcastTime: payload $payload";
|
Log 5, "CUL_MAX_BroadcastTime: payload $payload ". Dumper($modules{MAX}{defptr});
|
||||||
my $i = 1;
|
my $i = 1;
|
||||||
foreach my $addr (keys %{$modules{MAX}{defptr}}) {
|
foreach my $addr (keys %{$modules{MAX}{defptr}}) {
|
||||||
|
Log 5, "addr $addr";
|
||||||
my $dhash = $modules{MAX}{defptr}{$addr};
|
my $dhash = $modules{MAX}{defptr}{$addr};
|
||||||
#Check that
|
#Check that
|
||||||
#1. the MAX device dhash uses this MAX_CUL as IODev
|
#1. the MAX device dhash uses this MAX_CUL as IODev
|
||||||
#2. the MAX device is a Wall/HeatingThermostat
|
#2. the MAX device is a Wall/HeatingThermostat
|
||||||
if(exists($dhash->{IODev}) && $dhash->{IODev} == $hash
|
if(exists($dhash->{IODev}) && $dhash->{IODev} == $hash
|
||||||
&& $dhash->{type} ~~ [ "HeatingThermostat", "HeatingThermostatPlus", "WallMountedThermostat"] ) {
|
&& $dhash->{type} ~~ [ "HeatingThermostat", "HeatingThermostatPlus", "WallMountedThermostat"]) {
|
||||||
#We queue it at different times and do not send directly, because
|
CUL_MAX_SendTimeInformation($hash, $addr, $payload);
|
||||||
#sending them all in a row makes us not see the Acks
|
}
|
||||||
InternalTimer(gettimeofday()+3*$i++, "CUL_MAX_SendTimeInformationSender", [$hash, $addr, $payload], 0);
|
else {
|
||||||
|
Log 5, "Not sending to $addr, type $dhash->{type}, $dhash->{IODev}{NAME}"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user