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

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
This commit is contained in:
ntruchsess 2014-06-13 22:36:48 +00:00
parent 2bc5f31d28
commit 1a9a0f3109
6 changed files with 179 additions and 260 deletions

View File

@ -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);
}
};

View File

@ -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

View File

@ -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;

View File

@ -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;

View File

@ -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);
}
}
};

View File

@ -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;
}