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:
parent
2bc5f31d28
commit
1a9a0f3109
@ -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);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user