From 1a9a0f3109c1f52475e2ba0d9d4465e8af79996c Mon Sep 17 00:00:00 2001 From: ntruchsess <> Date: Fri, 13 Jun 2014 22:36:48 +0000 Subject: [PATCH] OWX_ASYNC: refactor scheduling (for DS2480), avoids looping behaviour Merge branch 'owx_async_scheduler' git-svn-id: https://svn.fhem.de/fhem/trunk@6108 2b470e98-0d58-463d-a4d8-8e2adae1ed80 --- fhem/FHEM/00_OWX_ASYNC.pm | 274 +++++++++++++++++++++----------------- fhem/FHEM/21_OWTHERM.pm | 16 +-- fhem/FHEM/OWX_DS2480.pm | 14 +- fhem/FHEM/OWX_Executor.pm | 65 +-------- fhem/FHEM/OWX_FRM.pm | 66 +-------- fhem/FHEM/OWX_SER.pm | 4 +- 6 files changed, 179 insertions(+), 260 deletions(-) diff --git a/fhem/FHEM/00_OWX_ASYNC.pm b/fhem/FHEM/00_OWX_ASYNC.pm index b4727d6c4..787f9d5c6 100644 --- a/fhem/FHEM/00_OWX_ASYNC.pm +++ b/fhem/FHEM/00_OWX_ASYNC.pm @@ -128,7 +128,7 @@ my %attrs = ( ); #-- some globals needed for the 1-Wire module -$owx_async_version=5.3; +$owx_async_version=5.4; #-- Debugging 0,1,2,3 $owx_async_debug=0; @@ -156,7 +156,7 @@ sub OWX_ASYNC_Initialize ($) { $hash->{SetFn} = "OWX_ASYNC_Set"; $hash->{AttrFn} = "OWX_ASYNC_Attr"; $hash->{NotifyFn} = "OWX_ASYNC_Notify"; - $hash->{ReadFn} = "OWX_ASYNC_Poll"; + $hash->{ReadFn} = "OWX_ASYNC_Read"; $hash->{ReadyFn} = "OWX_ASYNC_Ready"; $hash->{InitFn} = "OWX_ASYNC_Init"; $hash->{AttrList} = "dokick:0,1 interval IODev timeout"; @@ -274,6 +274,12 @@ sub OWX_ASYNC_Ready ($) { return 1; }; +sub OWX_ASYNC_Read ($) { + my $hash = shift; + OWX_ASYNC_Poll($hash); + OWX_ASYNC_RunTasks($hash); +}; + sub OWX_ASYNC_Poll ($) { my $hash = shift; if (defined $hash->{ASYNC}) { @@ -827,17 +833,10 @@ sub OWX_ASYNC_Kick($) { #-- Call us in n seconds again. InternalTimer(gettimeofday()+ $hash->{interval}, "OWX_ASYNC_Kick", $hash,0); - #-- Only if we have the dokick attribute set to 1 - if (main::AttrVal($hash->{NAME},"dokick",0)) { - eval { - OWX_ASYNC_ScheduleMaster( $hash, PT_THREAD(\&OWX_ASYNC_PT_Kick), $hash ); - }; - Log3 $hash->{NAME},3,"OWX_ASYNC_Kick: ".GP_Catch($@) if $@; - } - - if (OWX_ASYNC_Search($hash)) { - OWX_ASYNC_Alarms($hash); + eval { + OWX_ASYNC_ScheduleMaster( $hash, PT_THREAD(\&OWX_ASYNC_PT_Kick), $hash ); }; + Log3 $hash->{NAME},3,"OWX_ASYNC_Kick: ".GP_Catch($@) if $@; return 1; } @@ -846,23 +845,29 @@ sub OWX_ASYNC_PT_Kick($) { my ($thread,$hash) = @_; PT_BEGIN($thread); - Log3 $hash->{NAME},5,"OWX_ASYNC_PT_Kick: kicking DS14B20 temperature conversion"; - #-- issue the skip ROM command \xCC followed by start conversion command \x44 - unless (OWX_ASYNC_Execute($hash,$thread,1,undef,"\x44",0)) { - PT_EXIT("OWX_ASYNC: Failure in temperature conversion"); - } - my ($seconds,$micros) = gettimeofday; - $thread->{execute_delayed} = [$seconds+1,$micros]; - #PT_YIELD_UNTIL(defined $thread->{ExecuteResponse}); - PT_YIELD_UNTIL(tv_interval($thread->{execute_delayed})>=0); - - GP_ForallClients($hash,sub { - my ($client) = @_; - if ($client->{TYPE} eq "OWTHERM" and AttrVal($client->{NAME},"tempConv","") eq "onkick" ) { - Log3 $client->{NAME},5,"OWX_ASYNC_PT_Kick: doing tempConv for $client->{NAME}"; - OWX_ASYNC_Schedule($client, PT_THREAD(\&OWXTHERM_PT_GetValues), $client ); + #-- Only if we have the dokick attribute set to 1 + if (main::AttrVal($hash->{NAME},"dokick",0)) { + Log3 $hash->{NAME},5,"OWX_ASYNC_PT_Kick: kicking DS14B20 temperature conversion"; + #-- issue the skip ROM command \xCC followed by start conversion command \x44 + unless (OWX_ASYNC_Execute($hash,$thread,1,undef,"\x44",0)) { + PT_EXIT("OWX_ASYNC: Failure in temperature conversion"); } - },undef); + $thread->{ExecuteTime} = gettimeofday()+1; + PT_YIELD_UNTIL(defined $thread->{ExecuteResponse} and (gettimeofday() >= $thread->{ExecuteTime})); + + GP_ForallClients($hash,sub { + my ($client) = @_; + if ($client->{TYPE} eq "OWTHERM" and AttrVal($client->{NAME},"tempConv","") eq "onkick" ) { + Log3 $client->{NAME},5,"OWX_ASYNC_PT_Kick: doing tempConv for $client->{NAME}"; + OWX_ASYNC_Schedule($client, PT_THREAD(\&OWXTHERM_PT_GetValues), $client ); + } + },undef); + } + + #TODO OWX_ASYNC_Search allways returns 1 when busmaster is active + if (OWX_ASYNC_Search($hash)) { + OWX_ASYNC_Alarms($hash); + }; PT_END; } @@ -978,59 +983,21 @@ sub OWX_ASYNC_Verify ($$) { # ######################################################################################## -sub OWX_Execute($$$$$$$) { - my ( $hash, $context, $reset, $owx_dev, $data, $numread, $delay ) = @_; - if (my $executor = $hash->{ASYNC}) { - delete $hash->{replies}{$owx_dev}{$context} if (defined $owx_dev and defined $context); - return $executor->execute( $hash, $context, $reset, $owx_dev, $data, $numread, $delay ); - } else { - return 0; - } -}; - sub OWX_ASYNC_Execute($$$$$$) { my ( $hash, $context, $reset, $owx_dev, $data, $numread ) = @_; if (my $executor = $hash->{ASYNC}) { delete $context->{ExecuteResponse}; - return $executor->execute( $hash, $context, $reset, $owx_dev, $data, $numread, undef ); + my $now = gettimeofday(); + #TODO implement propper timeout based on timeout-attribute + #my $timeoutms = AttrVal($hash->{NAME},"timeout",1000); + $context->{TimeoutTime} = $now+2; + Log3 ($hash->{NAME},5,sprintf("OWX_ASYNC_Execute: set TimeoutTime: %.6f, now: %.6f",$context->{TimeoutTime},$now)) if ($owx_async_debug); + return $executor->execute( $hash, $context, $reset, $owx_dev, $data, $numread ); } else { return 0; } }; -####################################################################################### -# -# OWX_AwaitExecuteResponse - Wait for the result of a call to OWX_Execute -# -# Parameter hash = hash of bus master -# context = correlates the response with the call to OWX_Execute -# owx_dev = 1-Wire-address of device that is to be read -# -# Return: Data that has been read from device -# undef if timeout occours -# -######################################################################################## - -sub OWX_AwaitExecuteResponse($$$) { - my ($hash,$context,$owx_dev) = @_; - #-- get the interface - my $async = $hash->{ASYNC}; - - #-- Discover all devices on the 1-Wire bus, they will be found in $hash->{DEVS} - if (defined $async and defined $owx_dev and defined $context) { - my $times = AttrVal($hash->{NAME},"timeout",5000) / 50; #timeout in ms, defaults to 1 sec - for (my $i=0;$i<$times;$i++) { - if(! defined $hash->{replies}{$owx_dev}{$context}) { - select (undef,undef,undef,0.05); - $async->poll($hash); - } else { - return $hash->{replies}{$owx_dev}{$context}; - }; - }; - }; - return undef; -}; - ######################################################################################## # # OWX_ASYNC_AfterExecute - is called when a query initiated by OWX_Execute successfully returns @@ -1065,39 +1032,18 @@ sub OWX_ASYNC_AfterExecute($$$$$$$$) { ", numread: ".(defined $numread ? $numread : "undef"). ", readdata: ".(defined $readdata ? unpack ("H*",$readdata) : "undef")); - if (defined $owx_dev) { - if ( defined $context and ref $context eq "ProtoThreads" ) { - $context->{ExecuteResponse} = { - success => $success, - 'reset' => $reset, - writedata => $writedata, - readdata => $readdata, - numread => $numread, - }; - } else { - foreach my $d ( sort keys %main::defs ) { - if ( my $hash = $main::defs{$d} ) { - if ( defined( $hash->{ROM_ID} ) - && defined( $hash->{IODev} ) - && $hash->{IODev} == $master - && $hash->{ROM_ID} eq $owx_dev ) { - if ($main::modules{$hash->{TYPE}}{AfterExecuteFn}) { - my $ret = CallFn($d,"AfterExecuteFn", $hash, $context, $success, $reset, $owx_dev, $writedata, $numread, $readdata); - Log3 ($master->{NAME},4,"OWX_ASYNC_AfterExecute [".(defined $owx_dev ? $owx_dev : "unknown owx device")."]: $ret") if ($ret); - if ($success) { - readingsSingleUpdate($hash,"PRESENT",1,1) unless ($hash->{PRESENT}); - } else { - readingsSingleUpdate($hash,"PRESENT",0,1) if ($hash->{PRESENT}); - } - } - } - } - } - if (defined $context) { - $master->{replies}{$owx_dev}{$context} = $readdata; - } - } - } + if ( defined $context and ref $context eq "ProtoThreads" ) { + $context->{ExecuteResponse} = { + success => $success, + 'reset' => $reset, + writedata => $writedata, + readdata => $readdata, + numread => $numread, + }; + delete $context->{TimeoutTime}; + } else { + die "OWX_ASYNC_AfterExecute: $context is not a ProtoThread"; + } }; sub OWX_ASYNC_Schedule($$@) { @@ -1106,52 +1052,140 @@ sub OWX_ASYNC_Schedule($$@) { die "OWX_ASYNC_Schedule: Master not Active" unless $master->{STATE} eq "Active"; my $owx_dev = $hash->{ROM_ID}; $task->{ExecuteArgs} = \@args; + my $now = gettimeofday(); + $task->{ExecuteTime} = $now; if (defined $master->{tasks}->{$owx_dev}) { push @{$master->{tasks}->{$owx_dev}}, $task; } else { $master->{tasks}->{$owx_dev} = [$task]; } - main::InternalTimer(gettimeofday(), "OWX_ASYNC_RunTasks", $master,0); + main::InternalTimer($now, "OWX_ASYNC_RunTasks", $master,0); }; sub OWX_ASYNC_ScheduleMaster($$@) { my ( $master, $task, @args ) = @_; die "OWX_ASYNC_Schedule: Master not Active" unless $master->{STATE} eq "Active"; $task->{ExecuteArgs} = \@args; + my $now = gettimeofday(); + $task->{ExecuteTime} = $now; if (defined $master->{tasks}->{master}) { push @{$master->{tasks}->{master}}, $task; } else { $master->{tasks}->{master} = [$task]; } - main::InternalTimer(gettimeofday(), "OWX_ASYNC_RunTasks", $master,0); + main::InternalTimer($now, "OWX_ASYNC_RunTasks", $master,0); }; sub OWX_ASYNC_RunTasks($) { my ( $master ) = @_; - my ( $owx_dev, $queue ); if ($master->{STATE} eq "Active") { - foreach my $owx_dev (keys %{$master->{tasks}}) { - my $queue = $master->{tasks}->{$owx_dev}; - if (@$queue) { - my $task = $queue->[0]; + Log3 ($master->{NAME},5,"OWX_ASYNC_RunTasks: ".((defined $master->{".currenttaskdevice"}) ? $master->{".currenttaskdevice"} : "-undefined-")." called") if ($owx_async_debug); + my $now = gettimeofday(); + my $currentqueue; + my $currentdevice = $master->{".currenttaskdevice"}; + $currentqueue = $master->{tasks}->{$currentdevice} if (defined $currentdevice); + do { + unless (defined $currentqueue and @$currentqueue) { + foreach my $owx_dev (keys %{$master->{tasks}}) { + my $queue = $master->{tasks}->{$owx_dev}; + if (@$queue) { + # if task is eligible to run now: + if (defined ($queue->[0]->{ExecuteTime}) and ($now >= $queue->[0]->{ExecuteTime})) { + $currentqueue = $queue; + $currentdevice = $owx_dev; + Log3 ($master->{NAME},5,"OWX_ASYNC_RunTasks: $owx_dev identified") if ($owx_async_debug); + last; + } + } else { + delete $master->{tasks}->{$owx_dev}; + } + } + } + if (defined $currentqueue and @$currentqueue) { + my $task = $currentqueue->[0]; + my $timeout = $task->{TimeoutTime}; my $ret; eval { $ret = $task->PT_SCHEDULE(@{$task->{ExecuteArgs}}); }; + # finished running or error: if (!$ret or $@) { - shift @$queue; - delete $master->{tasks}->{$owx_dev} unless @$queue; + shift @$currentqueue; + undef $currentqueue; my $msg = ($@) ? GP_Catch($@) : $task->PT_RETVAL(); if (defined $msg) { - Log3 ($master->{NAME},2,"OWX_ASYNC: Error running task for $owx_dev: $msg"); + Log3 ($master->{NAME},3,"OWX_ASYNC_RunTasks: $currentdevice Error running task: $msg"); + } else { + Log3 ($master->{NAME},5,"OWX_ASYNC_RunTasks: $currentdevice finished task"); + } + # waiting for ExecuteResponse: + } elsif (defined $task->{TimeoutTime}) { + #task timed out: + if ($now >= $task->{TimeoutTime}) { + shift @$currentqueue; + undef $currentqueue; + Log3 ($master->{NAME},3,"OWX_ASYNC_RunTasks: $currentdevice task timed out"); + Log3 ($master->{NAME},5,sprintf("OWX_ASYNC_RunTasks: $currentdevice TimeoutTime: %.6f, now: %.6f",$task->{TimeoutTime},$now)); + } else { + Log3 $master->{NAME},5,"OWX_ASYNC_RunTasks: $currentdevice waiting for data or timeout" if ($owx_async_debug); + #new timeout or timeout did change: + if (!defined $timeout or $timeout != $task->{TimeoutTime}) { + Log3 $master->{NAME},5,sprintf("OWX_ASYNC_RunTasks: $currentdevice schedule for timeout at %.6f",$task->{TimeoutTime}); + main::InternalTimer($task->{TimeoutTime}, "OWX_ASYNC_RunTasks", $master,0); + } + } + # or not finished running, no error but scheduled for future: + } elsif (defined $task->{ExecuteTime} and $now < $task->{ExecuteTime}) { + undef $currentqueue; + Log3 ($master->{NAME},5,"OWX_ASYNC_RunTasks: $currentdevice task not finished, next executetime: $task->{ExecuteTime}"); + } elsif ($owx_async_debug) { + Log3 $master->{NAME},5,"OWX_ASYNC_RunTasks: $currentdevice no action"; + } + if (defined $currentqueue and @$currentqueue) { + Log3 $master->{NAME},5,"OWX_ASYNC_RunTasks: $currentdevice exit loop" if ($owx_async_debug); + $master->{".currenttaskdevice"} = $currentdevice; + OWX_ASYNC_Poll($master); + return; + } elsif ($owx_async_debug) { + Log3 $master->{NAME},5,sprintf("OWX_ASYNC_RunTasks: -undefined- continue loop"); + } + } else { + my $nexttime; + foreach my $owx_dev (keys %{$master->{tasks}}) { + my $queue = $master->{tasks}->{$owx_dev}; + if (@$queue) { + my $nexttask = $queue->[0]; + # if task is scheduled for future: + if (defined $nexttask->{ExecuteTime}) { + $nexttime = $nexttask->{ExecuteTime} if (!defined $nexttime or ($nexttime > $nexttask->{ExecuteTime})); + $currentdevice = $owx_dev; + } + } else { + delete $master->{tasks}->{$owx_dev}; } } - OWX_ASYNC_Poll( $master ); - } else { - delete $master->{tasks}->{$owx_dev}; + if (defined $nexttime) { + if ($nexttime > $now) { + if (!defined $master->{".nexttasktime"} or $nexttime < $master->{".nexttasktime"} or $now >= $master->{".nexttasktime"}) { + Log3 $master->{NAME},5,sprintf("OWX_ASYNC_RunTasks: $currentdevice schedule next at %.6f",$nexttime); + main::InternalTimer($nexttime, "OWX_ASYNC_RunTasks", $master,0); + $master->{".nexttasktime"} = $nexttime; + } else { + Log3 $master->{NAME},5,sprintf("OWX_ASYNC_RunTasks: $currentdevice skip %.6f, allready scheduled at %.6f",$nexttime,$master->{".nexttasktime"}) if ($owx_async_debug); + } + } else { + delete $master->{".nexttasktime"}; + Log3 $master->{NAME},5,sprintf("OWX_ASYNC_RunTasks: $currentdevice nexttime at %.6f allready passed",$nexttime) if ($owx_async_debug); + } + } else { + Log3 $master->{NAME},5,sprintf("OWX_ASYNC_RunTasks: -undefined- no nexttime") if ($owx_async_debug); + } + delete $master->{".currenttaskdevice"}; + Log3 $master->{NAME},5,sprintf("OWX_ASYNC_RunTasks: -undefined- exit loop") if ($owx_async_debug); + OWX_ASYNC_Poll($master); + return; } - } - main::InternalTimer(gettimeofday(), "OWX_ASYNC_RunTasks", $master,0) if (keys %{$master->{tasks}}); + } while (1); } }; diff --git a/fhem/FHEM/21_OWTHERM.pm b/fhem/FHEM/21_OWTHERM.pm index eb65271ca..8a0112244 100755 --- a/fhem/FHEM/21_OWTHERM.pm +++ b/fhem/FHEM/21_OWTHERM.pm @@ -86,7 +86,7 @@ no warnings 'deprecated'; sub Log3($$$); sub AttrVal($$$); -my $owx_version="5.19"; +my $owx_version="5.20"; my %gets = ( "id" => "", @@ -1107,18 +1107,10 @@ sub OWXTHERM_PT_GetValues($@) { unless (OWX_ASYNC_Execute($master,$thread,1,$owx_dev,"\x44",0)) { PT_EXIT("$owx_dev not accessible for convert"); } - my ($seconds,$micros) = gettimeofday; + my $now = gettimeofday(); my $delay = $convtimes{AttrVal($name,"resolution",12)}; - my $len = length ($delay); #delay is millis, tv_address works with [sec,micros] - if ($len>3) { - $seconds += substr($delay,0,$len-3); - $micros += (substr ($delay,-3)*1000); - } else { - $micros += ($delay*1000); - } - $thread->{execute_delayed} = [$seconds,$micros]; - PT_WAIT_UNTIL(defined $thread->{ExecuteResponse}); - PT_YIELD_UNTIL(tv_interval($thread->{execute_delayed})>=0); + $thread->{ExecuteTime} = $now + $delay*0.001; + PT_YIELD_UNTIL(defined $thread->{ExecuteResponse} and (gettimeofday() >= $thread->{ExecuteTime})); } #-- NOW ask the specific device #-- issue the match ROM command \x55 and the read scratchpad command \xBE diff --git a/fhem/FHEM/OWX_DS2480.pm b/fhem/FHEM/OWX_DS2480.pm index 0b3cb3a71..a849c6863 100644 --- a/fhem/FHEM/OWX_DS2480.pm +++ b/fhem/FHEM/OWX_DS2480.pm @@ -126,17 +126,21 @@ sub read() { my $hwdevice = $serial->{hwdevice}; return undef unless (defined $hwdevice); - #-- read the data - looping for slow devices suggested by Joachim Herold + #-- read the data my ($count_in, $string_part) = $hwdevice->read(255); return undef if (not defined $count_in or not defined $string_part); $serial->{string_in} .= $string_part; $serial->{retcount} += $count_in; $serial->{num_reads}++; - if( $main::owx_async_debug > 1){ + if( $main::owx_async_debug > 1 ) { if ($count_in>0) { main::Log3($serial->{name},5, "OWX_DS2480 read: Loop no. $serial->{num_reads}, Receiving: ".unpack("H*",$string_part)); - } else { - main::Log3($serial->{name},5, "OWX_DS2480 read: Loop no. $serial->{num_reads}"); + } elsif ($main::owx_async_debug > 2) { + main::Log3($serial->{name},5, "OWX_DS2480 read: Loop no. $serial->{num_reads}, no data read:"); + foreach my $i (0..6) { + my ($package, $filename, $line, $subroutine, $hasargs, $wantarray, $evaltext, $is_require, $hints, $bitmask, $hinthash) = caller($i); + main::Log3($serial->{name},5, "$subroutine $filename $line"); + } } } return $count_in > 0 ? 1 : undef; @@ -158,7 +162,7 @@ sub response_ready() { sub start_query() { my ($serial) = @_; #read and discard any outstanding data from previous commands: - while($serial->read(255)) {}; + while($serial->read()) {}; $serial->{string_in} = ""; $serial->{num_reads} = 0; diff --git a/fhem/FHEM/OWX_Executor.pm b/fhem/FHEM/OWX_Executor.pm index 67bd0ca40..bb9e28e8d 100644 --- a/fhem/FHEM/OWX_Executor.pm +++ b/fhem/FHEM/OWX_Executor.pm @@ -50,15 +50,14 @@ sub verify($$) { } sub execute($$$$$$$) { - my ( $self, $hash, $context, $reset, $owx_dev, $data, $numread, $delay ) = @_; + my ( $self, $hash, $context, $reset, $owx_dev, $data, $numread ) = @_; if($self->{worker}->submit( { command => EXECUTE, context => $context, reset => $reset, address => $owx_dev, writedata => $data, - numread => $numread, - delay => $delay + numread => $numread }, $hash )) { $self->poll($hash); return 1; @@ -79,7 +78,6 @@ sub poll($) { my ( $self,$hash ) = @_; $self->read(); $self->{worker}->PT_SCHEDULE($hash); - $self->{worker}->scheduleNext($hash); } # start of worker code @@ -116,7 +114,7 @@ sub pt_main($) { my ( $self, $hash ) = @_; my $item = $self->{item}; PT_BEGIN($self); - PT_YIELD_UNTIL($item = $self->nextItem($hash)); + PT_WAIT_UNTIL($item = $self->nextItem($hash)); $self->{item} = $item; REQUEST_HANDLER: { @@ -160,28 +158,6 @@ sub pt_main($) { my @result = split (//, $res); my $readdata = 9+$writelen < @result ? substr($res,9+$writelen) : ""; main::OWX_ASYNC_AfterExecute($hash,$item->{context},1,$item->{reset},$item->{address},$item->{writedata},$item->{numread},$readdata); - if (my $delay = $item->{delay}) { - my ($seconds,$micros) = gettimeofday; - my $len = length ($delay); #delay is millis, tv_address works with [sec,micros] - if ($len>3) { - $seconds += substr($delay,0,$len-3); - $micros += (substr ($delay,-3)*1000); - } else { - $micros += ($delay*1000); - } - - if (my $address = $item->{address}) { - my $delayed = $self->{delayed}; - unless ($delayed->{$address}) { - $delayed->{$address} = { items => [] }; - } - $delayed->{$address}->{'until'} = [$seconds,$micros]; - main::Log3 $hash->{NAME},5,"delay after $item->{context} until: $seconds,$micros" - } else { - $self->{execute_delayed} = [$seconds,$micros]; - PT_YIELD_UNTIL(tv_interval($self->{execute_delayed})>=0); - } - } PT_EXIT; }; @@ -196,24 +172,7 @@ sub pt_main($) { sub nextItem($) { my ( $self,$hash ) = @_; - my ($item,$nexttime,$nextaddress); - my $delayed = $self->{delayed}; - foreach my $address (keys %$delayed) { - next if (tv_interval($delayed->{$address}->{'until'}) < 0); - my $delayed_items = $delayed->{$address}->{'items'}; - $item = shift @$delayed_items; - delete $delayed->{$address} unless @$delayed_items; - last; - }; - unless ($item) { - $item = shift @{$self->{commands}}; - if ($item and my $address = $item->{address}) { - if ($delayed->{$address}) { - push @{$delayed->{$address}->{'items'}},$item; - return undef; - }; - }; - }; + my $item = shift @{$self->{commands}}; if ($item) { if($item->{context}) { main::Log3 $hash->{NAME},5,"OWX_Executor: item $item->{context} for ".(defined $item->{address} ? $item->{address} : "---")." eligible to run"; @@ -224,20 +183,4 @@ sub nextItem($) { return $item; } -sub scheduleNext($) { - my ($self,$hash) = @_; - my $delayed = $self->{delayed}; - my $nexttime; - foreach my $address (keys %$delayed) { - if (my $until = $delayed->{$address}->{'until'}) { - $nexttime = $until unless ($nexttime and tv_interval($nexttime,$until) < 0); - } - }; - if ($nexttime) { - main::RemoveInternalTimer($hash); - main::Log3 $hash->{NAME},5,"schedule next item at $nexttime->[0].$nexttime->[1] ".tv_interval($nexttime); - main::InternalTimer( "$nexttime->[0].$nexttime->[1]", "OWX_ASYNC_Poll", $hash, 0 ); - } -} - 1; diff --git a/fhem/FHEM/OWX_FRM.pm b/fhem/FHEM/OWX_FRM.pm index 9cb94a93d..f43517050 100644 --- a/fhem/FHEM/OWX_FRM.pm +++ b/fhem/FHEM/OWX_FRM.pm @@ -59,7 +59,6 @@ sub Define($$) { $self->{id} = 0; $self->{name} = $hash->{NAME}; $self->{hash} = $hash; - $self->{delayed} = {}; return undef; } @@ -107,7 +106,7 @@ COMMAND_HANDLER: { my $id = $data->{id}; my $request = ( defined $id ) ? $self->{requests}->{$id} : undef; unless ( defined $request ) { - return unless ( defined $data->{device} ); + last unless ( defined $data->{device} ); my $owx_device = FRM_OWX_firmata_to_device( $data->{device} ); my %requests = %{ $self->{requests} }; foreach my $key ( keys %requests ) { @@ -118,7 +117,7 @@ COMMAND_HANDLER: { }; }; }; - return unless ( defined $request ); + last unless ( defined $request ); my $owx_data = pack "C*", @{ $data->{data} }; my $owx_device = $request->{device}; my $context = $request->{context}; @@ -143,6 +142,7 @@ COMMAND_HANDLER: { last; }; }; + main::OWX_ASYNC_RunTasks($self->{hash}); }; ########### functions implementing interface to OWX ########## @@ -203,35 +203,8 @@ sub alarms($) { return $success; }; -sub execute($$$$$$$) { - my ( $self, $hash, $context, $reset, $owx_dev, $data, $numread, $delay ) = @_; - - my $delayed = $self->{delayed}; - my $queue = $delayed->{$owx_dev} if defined $owx_dev; - - if ( $queue and @{$queue->{items}} ) { - if ( $context or $reset or $data or $numread or $delay ) { - push @{$queue->{items}}, { - context => $context, - 'reset' => $reset, - device => $owx_dev, - data => $data, - numread => $numread, - delay => $delay - }; - }; - if (!( defined $queue->{'until'} ) or ( tv_interval( $queue->{'until'} ) >= 0 ) ) { - my $item = shift @{$queue->{items}}; - $context = $item->{context}; - $reset = $item->{'reset'}; - $data = $item->{data}; - $numread = $item->{numread}; - $delay = $item->{delay}; - } else { - return 1; - } - } - return 1 unless ( $context or $reset or $data or $numread or $delay ); +sub execute($$$$$$) { + my ( $self, $hash, $context, $reset, $owx_dev, $data, $numread ) = @_; my $success = undef; @@ -266,32 +239,9 @@ sub execute($$$$$$$) { #$self->exit($hash); }; - if ($delay and $success) { - unless ($queue) { - $queue = { items => [] } ; - $delayed->{$owx_dev} = $queue; - } - my ( $seconds, $micros ) = gettimeofday; - my $len = length($delay); #delay is millis, tv_address works with [sec,micros] - if ( $len > 3 ) { - $seconds += substr( $delay, 0, $len - 3 ); - $micros += ( substr( $delay, $len - 3 ) * 1000 ); - } else { - $micros += ( $delay * 1000 ); - } - $queue->{'until'} = [ $seconds, $micros ]; - main::InternalTimer( "$seconds.$micros", "OWX_ASYNC_Poll", $hash, 0 ); - } else { - if ($queue) { - if (@{$queue->{items}}) { - delete( $queue->{'until'} ); - } else { - delete $delayed->{$owx_dev}; - } - } - } unless ($numread) { main::OWX_ASYNC_AfterExecute( $hash, $context, $success, $reset, $owx_dev, $data, $numread, "" ); + main::InternalTimer(gettimeofday(), "OWX_ASYNC_RunTasks", $hash,0); } return $success; }; @@ -305,10 +255,6 @@ sub poll($) { my ( $self, $hash ) = @_; if ( my $frm = $hash->{IODev} ) { main::FRM_poll($frm); - foreach my $address ( keys %{$self->{delayed}} ) { - $self->execute( $hash, undef, undef, $address, undef, undef, undef ); - main::FRM_poll($frm); - } } }; diff --git a/fhem/FHEM/OWX_SER.pm b/fhem/FHEM/OWX_SER.pm index 9cbf79435..41ed177df 100644 --- a/fhem/FHEM/OWX_SER.pm +++ b/fhem/FHEM/OWX_SER.pm @@ -101,9 +101,9 @@ sub Define ($$) { if ( $dev !~ m/\@\d*/ ){ $hash->{DeviceName} = $dev."\@9600"; } - $dev = split('@',$dev); + my ($device,$baudrate) = split('@',$dev); #-- let fhem.pl MAIN call OWX_Ready when setup is done. - $main::readyfnlist{"$hash->{NAME}.$dev"} = $hash; + $main::readyfnlist{"$hash->{NAME}.$device"} = $hash; return undef; }