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

OWX_ASYNC: cleanup and refactor interface to busmaster-classes (do all nested protothreads)

Merge branch 'owx_protothreads'

git-svn-id: https://svn.fhem.de/fhem/trunk@6259 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
ntruchsess 2014-07-15 16:44:35 +00:00
parent 1d098fe7c6
commit fbf43ce944
13 changed files with 2332 additions and 2321 deletions

View File

@ -128,7 +128,7 @@ my %attrs = (
); );
#-- some globals needed for the 1-Wire module #-- some globals needed for the 1-Wire module
$owx_async_version=5.4; $owx_async_version=5.5;
#-- Debugging 0,1,2,3 #-- Debugging 0,1,2,3
$owx_async_debug=0; $owx_async_debug=0;
@ -251,7 +251,7 @@ sub OWX_ASYNC_Attr(@) {
return $ret; return $ret;
} }
sub OWX_ASYNC_Notify { sub OWX_ASYNC_Notify ($$) {
my ($hash,$dev) = @_; my ($hash,$dev) = @_;
my $name = $hash->{NAME}; my $name = $hash->{NAME};
my $type = $hash->{TYPE}; my $type = $hash->{TYPE};
@ -276,12 +276,14 @@ sub OWX_ASYNC_Ready ($) {
sub OWX_ASYNC_Read ($) { sub OWX_ASYNC_Read ($) {
my $hash = shift; my $hash = shift;
Log3 ($hash->{NAME},5,"OWX_ASYNC_Read") if ($owx_async_debug > 2);
OWX_ASYNC_Poll($hash); OWX_ASYNC_Poll($hash);
OWX_ASYNC_RunTasks($hash); OWX_ASYNC_RunTasks($hash);
}; };
sub OWX_ASYNC_Poll ($) { sub OWX_ASYNC_Poll ($) {
my $hash = shift; my $hash = shift;
Log3 ($hash->{NAME},5,"OWX_ASYNC_Poll") if ($owx_async_debug > 2);
if (defined $hash->{ASYNC}) { if (defined $hash->{ASYNC}) {
$hash->{ASYNC}->poll($hash); $hash->{ASYNC}->poll($hash);
}; };
@ -326,56 +328,35 @@ sub OWX_ASYNC_Disconnected($) {
#TODO fix OWX_ASYNC_Alarms return value on failure #TODO fix OWX_ASYNC_Alarms return value on failure
######################################################################################## ########################################################################################
sub OWX_ASYNC_Alarms ($) { sub OWX_ASYNC_PT_Alarms ($) {
my ($hash) = @_; my ($hash) = @_;
#-- get the interface #-- get the interface
my $name = $hash->{NAME};
my $async = $hash->{ASYNC}; my $async = $hash->{ASYNC};
my $res;
#-- Discover all devices on the 1-Wire bus, they will be found in $hash->{DEVS}
if (defined $async) { if (defined $async) {
delete $hash->{ALARMDEVS}; return PT_THREAD(sub {
return $async->alarms($hash); my ($thread) = @_;
PT_BEGIN($thread);
$thread->{pt_alarms} = $async->get_pt_alarms();
$thread->{TimeoutTime} = gettimeofday()+2; #TODO: implement attribute-based timeout
PT_WAIT_THREAD($thread->{pt_alarms});
delete $thread->{TimeoutTime};
die $thread->{pt_alarms}->PT_CAUSE() if ($thread->{pt_alarms}->PT_STATE() == PT_ERROR);
if (defined (my $alarmed_devs = $thread->{pt_alarms}->PT_RETVAL())) {
OWX_ASYNC_AfterAlarms($hash,$alarmed_devs);
};
PT_END;
});
} else { } else {
#-- interface error
my $owx_interface = $hash->{INTERFACE}; my $owx_interface = $hash->{INTERFACE};
if( !(defined($owx_interface))){ if( !defined($owx_interface) ) {
return undef; die "OWX: Alarms called with undefined interface on bus $hash->{NAME}";
} else { } else {
return "OWX: Alarms called with unknown interface $owx_interface on bus $name"; die "OWX: Alarms called with unknown interface $owx_interface on bus $hash->{NAME}";
} }
} }
};
#######################################################################################
#
# OWX_ASYNC_AwaitAlarmsResponse - Wait for the result of a call to OWX_ASYNC_Alarms
#
# Parameter hash = hash of bus master
#
# Return: Reference to Array of alarmed 1-Wire-addresses found on 1-Wire bus.
# undef if timeout occours
#
########################################################################################
sub OWX_ASYNC_AwaitAlarmsResponse($) {
my ($hash) = @_;
#-- get the interface
my $async = $hash->{ASYNC};
if (defined $async) {
my $times = AttrVal($hash->{NAME},"timeout",5000) / 50; #timeout in ms, defaults to 1 sec #TODO add attribute timeout?
for (my $i=0;$i<$times;$i++) {
if(! defined $hash->{ALARMDEVS} ) {
select (undef,undef,undef,0.05);
$async->poll($hash);
} else {
return $hash->{ALARMDEVS};
};
};
};
return undef;
} }
######################################################################################## ########################################################################################
@ -395,63 +376,22 @@ sub OWX_ASYNC_AwaitAlarmsResponse($) {
sub OWX_ASYNC_AfterAlarms($$) { sub OWX_ASYNC_AfterAlarms($$) {
my ($hash,$alarmed_devs) = @_; my ($hash,$alarmed_devs) = @_;
$hash->{ALARMDEVS} = $alarmed_devs; my @alarmed_devnames = ();
GP_ForallClients($hash,sub { GP_ForallClients($hash,sub {
my ($hash,$devs) = @_; my ($client) = @_;
my $romid = $hash->{ROM_ID}; my $romid = $client->{ROM_ID};
if (grep {/$romid/} @$devs) { Log3 ($client->{IODev}->{NAME},5,"OWX_ASYNC_AfterAlarms client NAME: $client->{NAME}, ROM_ID: $romid, ALARM: $client->{ALARM}, alarmed_devs: [".join(",",@$alarmed_devs)."]") if ($owx_async_debug>2);
readingsSingleUpdate($hash,"alarm",1,!$hash->{ALARM}); if (grep {$romid eq $_} @$alarmed_devs) {
$hash->{ALARM}=1; readingsSingleUpdate($client,"alarm",1,!$client->{ALARM});
$client->{ALARM}=1;
push (@alarmed_devnames,$client->{NAME});
} else { } else {
readingsSingleUpdate($hash,"alarm",0, $hash->{ALARM}); readingsSingleUpdate($client,"alarm",0, $client->{ALARM});
$hash->{ALARM}=0; $client->{ALARM}=0;
}
},$alarmed_devs);
};
########################################################################################
#
# OWX_ASYNC_DiscoverAlarms - Search for devices on the 1-Wire bus which have the alarm flag set
#
# Parameter hash = hash of bus master
#
# Return: Message or list of alarmed devices
#
########################################################################################
sub OWX_ASYNC_DiscoverAlarms($) {
my ($hash) = @_;
if (OWX_ASYNC_Alarms($hash)) {
if (my $alarmed_devs = OWX_ASYNC_AwaitAlarmsResponse($hash)) {
my @owx_alarm_names=();
my $name = $hash->{NAME};
if( $alarmed_devs == 0){
return "OWX: No alarmed 1-Wire devices found on bus $name";
}
#-- walk through all the devices to get their proper fhem names
foreach my $fhem_dev (sort keys %main::defs) {
#-- skip if busmaster
next if( $name eq $main::defs{$fhem_dev}{NAME} );
#-- all OW types start with OW
next if( substr($main::defs{$fhem_dev}{TYPE},0,2) ne "OW");
foreach my $owx_dev (@{$alarmed_devs}) {
#-- two pieces of the ROM ID found on the bus
my $owx_rnf = substr($owx_dev,3,12);
my $owx_f = substr($owx_dev,0,2);
my $id_owx = $owx_f.".".$owx_rnf;
#-- skip if not in alarm list
if( $owx_dev eq $main::defs{$fhem_dev}{ROM_ID} ){
$main::defs{$fhem_dev}{STATE} = "Alarmed";
push(@owx_alarm_names,$main::defs{$fhem_dev}{NAME});
}
}
}
#-- so far, so good - what do we want to do with this ?
return "OWX: ".scalar(@owx_alarm_names)." alarmed 1-Wire devices found on bus $name (".join(",",@owx_alarm_names).")";
}
} }
});
$hash->{ALARMDEVS} = \@alarmed_devnames;
Log3 ($hash->{NAME},5,"OWX_ASYNC_AfterAlarms: ALARMDEVS = [".join(",",@alarmed_devnames)."]") if ($owx_async_debug>2);
}; };
######################################################################################## ########################################################################################
@ -465,14 +405,34 @@ sub OWX_ASYNC_DiscoverAlarms($) {
# #
######################################################################################## ########################################################################################
sub OWX_ASYNC_Discover ($) { sub OWX_ASYNC_PT_Discover ($) {
my ($hash) = @_; my ($hash) = @_;
if (OWX_ASYNC_Search($hash)) {
if (my $owx_devices = OWX_ASYNC_AwaitSearchResponse($hash)) { #-- get the interface
return OWX_ASYNC_AutoCreate($hash,$owx_devices); my $async = $hash->{ASYNC};
#-- Discover all devices on the 1-Wire bus, they will be found in $hash->{DEVS}
if (defined $async) {
return PT_THREAD(sub {
my ($thread) = @_;
PT_BEGIN($thread);
$thread->{pt_discover} = $async->get_pt_discover();
$thread->{TimeoutTime} = gettimeofday()+2; #TODO: implement attribute-based timeout
PT_WAIT_THREAD($thread->{pt_discover});
delete $thread->{TimeoutTime};
die $thread->{pt_discover}->PT_CAUSE() if ($thread->{pt_discover}->PT_STATE() == PT_ERROR);
if (my $owx_devices = $thread->{pt_discover}->PT_RETVAL()) {
PT_EXIT(OWX_ASYNC_AutoCreate($hash,$owx_devices));
}; };
PT_END;
});
} else { } else {
return undef; my $owx_interface = $hash->{INTERFACE};
if( !defined($owx_interface) ) {
die "OWX: Discover called with undefined interface on bus $hash->{NAME}";
} else {
die "OWX: Discover called with unknown interface $owx_interface on bus $hash->{NAME}";
}
} }
} }
@ -486,61 +446,37 @@ sub OWX_ASYNC_Discover ($) {
# #
######################################################################################## ########################################################################################
sub OWX_ASYNC_Search($) { sub OWX_ASYNC_PT_Search($) {
my ($hash) = @_; my ($hash) = @_;
my $res;
my $ow_dev;
#-- get the interface #-- get the interface
my $async = $hash->{ASYNC}; my $async = $hash->{ASYNC};
#-- Discover all devices on the 1-Wire bus, they will be found in $hash->{DEVS} #-- Discover all devices on the 1-Wire bus, they will be found in $hash->{DEVS}
if (defined $async) { if (defined $async) {
delete $hash->{DEVS}; return PT_THREAD(sub {
return $async->discover($hash); my ($thread) = @_;
PT_BEGIN($thread);
$thread->{pt_discover} = $async->get_pt_discover();
$thread->{TimeoutTime} = gettimeofday()+2; #TODO: implement attribute-based timeout
PT_WAIT_THREAD($thread->{pt_discover});
delete $thread->{TimeoutTime};
die $thread->{pt_discover}->PT_CAUSE() if ($thread->{pt_discover}->PT_STATE() == PT_ERROR);
if (defined (my $owx_devs = $thread->{pt_discover}->PT_RETVAL())) {
OWX_ASYNC_AfterSearch($hash,$owx_devs);
}
PT_END;
});
} else { } else {
my $owx_interface = $hash->{INTERFACE}; my $owx_interface = $hash->{INTERFACE};
if( !defined($owx_interface) ) { if( !defined($owx_interface) ) {
return undef; die "OWX: Search called with undefined interface on bus $hash->{NAME}";
} else { } else {
Log3 ($hash->{NAME},3,"OWX: Search called with unknown interface $owx_interface"); die "OWX: Search called with unknown interface $owx_interface on bus $hash->{NAME}";
return undef;
} }
} }
} }
#######################################################################################
#
# OWX_ASYNC_AwaitSearchResponse - Wait for the result of a call to OWX_ASYNC_Search
#
# Parameter hash = hash of bus master
#
# Return: Reference to Array of 1-Wire-addresses found on 1-Wire bus.
# undef if timeout occours
#
########################################################################################
sub OWX_ASYNC_AwaitSearchResponse($) {
my ($hash) = @_;
#-- 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) {
my $times = AttrVal($hash->{NAME},"timeout",5000) / 50; #timeout in ms, defaults to 1 sec #TODO add attribute timeout?
for (my $i=0;$i<$times;$i++) {
if(! defined $hash->{DEVS} ) {
select (undef,undef,undef,0.05);
$async->poll($hash);
} else {
return $hash->{DEVS};
};
};
};
return undef;
};
######################################################################################## ########################################################################################
# #
# OWX_ASYNC_AfterSearch - is called when the search initiated by OWX_ASYNC_Search successfully returns # OWX_ASYNC_AfterSearch - is called when the search initiated by OWX_ASYNC_Search successfully returns
@ -558,20 +494,24 @@ sub OWX_ASYNC_AwaitSearchResponse($) {
sub OWX_ASYNC_AfterSearch($$) { sub OWX_ASYNC_AfterSearch($$) {
my ($hash,$owx_devs) = @_; my ($hash,$owx_devs) = @_;
if (defined $owx_devs and (ref($owx_devs) eq "ARRAY")) { # if (defined $owx_devs and (ref($owx_devs) eq "ARRAY")) {
$hash->{DEVS} = $owx_devs; my @devnames = ();
GP_ForallClients($hash,sub { GP_ForallClients($hash,sub {
my ($hash,$devs) = @_; my ($client) = @_;
my $romid = $hash->{ROM_ID}; my $romid = $client->{ROM_ID};
if (grep {/$romid/} @$devs) { Log3 ($client->{IODev}->{NAME},5,"OWX_ASYNC_AfterSearch client NAME: $client->{NAME}, ROM_ID: $romid, PRESENT: $client->{PRESENT}, devs: [".join(",",@$owx_devs)."]") if ($owx_async_debug>2);
readingsSingleUpdate($hash,"present",1,!$hash->{PRESENT}); if (grep {$romid eq $_} @$owx_devs) {
$hash->{PRESENT} = 1; readingsSingleUpdate($client,"present",1,!$client->{PRESENT});
$client->{PRESENT} = 1;
push (@devnames,$client->{NAME});
} else { } else {
readingsSingleUpdate($hash,"present",0,$hash->{PRESENT}); readingsSingleUpdate($client,"present",0,$client->{PRESENT});
$hash->{PRESENT} = 0; $client->{PRESENT} = 0;
}
},$owx_devs);
} }
});
$hash->{DEVS} = \@devnames;
Log3 ($hash->{NAME},5,"OWX_ASYNC_AfterSearch: DEVS = [".join(",",@devnames)."]") if ($owx_async_debug>2);
# }
} }
######################################################################################## ########################################################################################
@ -633,6 +573,7 @@ sub OWX_ASYNC_AutoCreate($$) {
push(@owx_names,$exname); push(@owx_names,$exname);
#-- replace the ROM ID by the proper value including CRC #-- replace the ROM ID by the proper value including CRC
$main::defs{$fhem_dev}{ROM_ID}=$owx_dev; $main::defs{$fhem_dev}{ROM_ID}=$owx_dev;
readingsSingleUpdate($main::defs{$fhem_dev},"present",1,!$main::defs{$fhem_dev}->{PRESENT});
$main::defs{$fhem_dev}{PRESENT}=1; $main::defs{$fhem_dev}{PRESENT}=1;
$match = 1; $match = 1;
last; last;
@ -668,6 +609,7 @@ sub OWX_ASYNC_AutoCreate($$) {
} else{ } else{
select(undef,undef,undef,0.1); select(undef,undef,undef,0.1);
push(@owx_names,$acname); push(@owx_names,$acname);
readingsSingleUpdate($main::defs{$acname},"present",1,!$main::defs{$acname}->{PRESENT});
$main::defs{$acname}{PRESENT}=1; $main::defs{$acname}{PRESENT}=1;
#-- THIS IODev, default room (model is set in the device module) #-- THIS IODev, default room (model is set in the device module)
CommandAttr (undef,"$acname IODev $hash->{NAME}"); CommandAttr (undef,"$acname IODev $hash->{NAME}");
@ -727,16 +669,28 @@ sub OWX_ASYNC_Get($@) {
my $name = $hash->{NAME}; my $name = $hash->{NAME};
my $owx_dev = $hash->{ROM_ID}; my $owx_dev = $hash->{ROM_ID};
my ($task,$task_state);
if( $a[1] eq "alarms") { if( $a[1] eq "alarms") {
my $res = OWX_ASYNC_DiscoverAlarms($hash); eval {
#-- process result $task = OWX_ASYNC_PT_Alarms($hash);
return $res OWX_ASYNC_ScheduleMaster($hash,$task);
$task_state = OWX_ASYNC_RunToCompletion($hash,$task);
};
return $@ if $@;
return $task->PT_CAUSE() if ($task_state == PT_ERROR or $task_state == PT_CANCELED);
unless ( defined $hash->{ALARMDEVS} and @{$hash->{ALARMDEVS}}) {
return "OWX: No alarmed 1-Wire devices found on bus $name";
}
return "OWX: ".scalar(@{$hash->{ALARMDEVS}})." alarmed 1-Wire devices found on bus $name (".join(",",@{$hash->{ALARMDEVS}}).")";
} elsif( $a[1] eq "devices") { } elsif( $a[1] eq "devices") {
my $res = OWX_ASYNC_Discover($hash); eval {
#-- process result $task = OWX_ASYNC_PT_Discover($hash);
return $res OWX_ASYNC_ScheduleMaster($hash,$task);
$task_state = OWX_ASYNC_RunToCompletion($hash,$task);
};
return $@ if $@;
return ($task_state == PT_ERROR or $task_state == PT_CANCELED) ? $task->PT_CAUSE() : $task->PT_RETVAL();
} elsif( $a[1] eq "version") { } elsif( $a[1] eq "version") {
return $owx_async_version; return $owx_async_version;
@ -781,14 +735,22 @@ sub OWX_ASYNC_Init ($) {
return "OWX_ASYNC_Init failed: $err"; return "OWX_ASYNC_Init failed: $err";
}; };
$hash->{ASYNC} = $ret; $hash->{ASYNC} = $ret;
$hash->{ASYNC}->{debug} = $owx_async_debug;
$hash->{INTERFACE} = $owx->{interface}; $hash->{INTERFACE} = $owx->{interface};
} else { } else {
return "OWX: Init called with undefined interface"; return "OWX: Init called with undefined interface";
} }
$hash->{STATE} = "Active";
#-- Fourth step: discovering devices on the bus #-- Fourth step: discovering devices on the bus
# in 10 seconds discover all devices on the 1-Wire bus # in 10 seconds discover all devices on the 1-Wire bus
InternalTimer(gettimeofday()+10, "OWX_ASYNC_Discover", $hash,0); my $pt_discover = OWX_ASYNC_PT_Discover($hash);
$pt_discover->{ExecuteTime} = gettimeofday()+10;
eval {
OWX_ASYNC_ScheduleMaster($hash,$pt_discover);
};
return GP_Catch($@) if $@;
#-- Default settings #-- Default settings
$hash->{interval} = AttrVal($hash->{NAME},"interval",300); # kick every 5 minutes $hash->{interval} = AttrVal($hash->{NAME},"interval",300); # kick every 5 minutes
@ -800,7 +762,6 @@ sub OWX_ASYNC_Init ($) {
#readingsSingleUpdate($hash,"state","defined",1); #readingsSingleUpdate($hash,"state","defined",1);
#-- Intiate first alarm detection and eventually conversion in a minute or so #-- Intiate first alarm detection and eventually conversion in a minute or so
InternalTimer(gettimeofday() + $hash->{interval}, "OWX_ASYNC_Kick", $hash,0); InternalTimer(gettimeofday() + $hash->{interval}, "OWX_ASYNC_Kick", $hash,0);
$hash->{STATE} = "Active";
GP_ForallClients($hash,\&OWX_ASYNC_InitClient,undef); GP_ForallClients($hash,\&OWX_ASYNC_InitClient,undef);
return undef; return undef;
} }
@ -833,28 +794,26 @@ sub OWX_ASYNC_Kick($) {
#-- Call us in n seconds again. #-- Call us in n seconds again.
InternalTimer(gettimeofday()+ $hash->{interval}, "OWX_ASYNC_Kick", $hash,0); InternalTimer(gettimeofday()+ $hash->{interval}, "OWX_ASYNC_Kick", $hash,0);
unless ($hash->{".kickrunning"}) {
$hash->{".kickrunning"} = 1;
eval { eval {
OWX_ASYNC_ScheduleMaster( $hash, PT_THREAD(\&OWX_ASYNC_PT_Kick), $hash ); OWX_ASYNC_ScheduleMaster( $hash, PT_THREAD(sub {
}; my ($thread) = @_;
Log3 $hash->{NAME},3,"OWX_ASYNC_Kick: ".GP_Catch($@) if $@;
return 1;
}
sub OWX_ASYNC_PT_Kick($) {
my ($thread,$hash) = @_;
PT_BEGIN($thread); PT_BEGIN($thread);
#-- Only if we have the dokick attribute set to 1 #-- Only if we have the dokick attribute set to 1
if (main::AttrVal($hash->{NAME},"dokick",0)) { if (main::AttrVal($hash->{NAME},"dokick",0)) {
Log3 $hash->{NAME},5,"OWX_ASYNC_PT_Kick: kicking DS14B20 temperature conversion"; Log3 $hash->{NAME},5,"OWX_ASYNC_PT_Kick: kicking DS14B20 temperature conversion";
#-- issue the skip ROM command \xCC followed by start conversion command \x44 #-- issue the skip ROM command \xCC followed by start conversion command \x44
unless (OWX_ASYNC_Execute($hash,$thread,1,undef,"\x44",0)) { $thread->{pt_execute} = OWX_ASYNC_PT_Execute($hash,1,undef,"\x44",0);
PT_EXIT("OWX_ASYNC: Failure in temperature conversion"); $thread->{TimeoutTime} = gettimeofday()+2; #TODO: implement attribute-based timeout
} PT_WAIT_THREAD($thread->{pt_execute});
delete $thread->{TimeoutTime};
if ($thread->{pt_execute}->PT_STATE() == PT_ERROR) {
Log3 ($hash->{NAME},4,"OWX_ASYNC_PT_Kick: Failure in temperature conversion: ".$thread->{pt_execute}->PT_CAUSE());
} else {
$thread->{ExecuteTime} = gettimeofday()+1; $thread->{ExecuteTime} = gettimeofday()+1;
PT_YIELD_UNTIL(defined $thread->{ExecuteResponse} and (gettimeofday() >= $thread->{ExecuteTime})); PT_YIELD_UNTIL(gettimeofday() >= $thread->{ExecuteTime});
delete $thread->{ExecuteTime};
GP_ForallClients($hash,sub { GP_ForallClients($hash,sub {
my ($client) = @_; my ($client) = @_;
if ($client->{TYPE} eq "OWTHERM" and AttrVal($client->{NAME},"tempConv","") eq "onkick" ) { if ($client->{TYPE} eq "OWTHERM" and AttrVal($client->{NAME},"tempConv","") eq "onkick" ) {
@ -863,13 +822,30 @@ sub OWX_ASYNC_PT_Kick($) {
} }
},undef); },undef);
} }
}
#TODO OWX_ASYNC_Search allways returns 1 when busmaster is active $thread->{pt_search} = OWX_ASYNC_PT_Search($hash);
if (OWX_ASYNC_Search($hash)) { $thread->{TimeoutTime} = gettimeofday()+2; #TODO: implement attribute-based timeout
OWX_ASYNC_Alarms($hash); PT_WAIT_THREAD($thread->{pt_search});
delete $thread->{Timeouttime};
if ($thread->{pt_search}->PT_STATE() == PT_ERROR) {
Log3 ($hash->{NAME},4,"OWX_ASYNC_PT_Kick: Failure in search: ".$thread->{pt_search}->PT_CAUSE());
} else {
$thread->{pt_alarms} = OWX_ASYNC_PT_Alarms($hash);
$thread->{TimeoutTime} = gettimeofday()+2; #TODO: implement attribute-based timeout
PT_WAIT_THREAD($thread->{pt_alarms});
delete $thread->{TimeoutTime};
if ($thread->{pt_alarms}->PT_STATE() == PT_ERROR) {
Log3 ($hash->{NAME},4,"OWX_ASYNC_PT_Kick: Failure in alarm-search: ".$thread->{pt_alarms}->PT_CAUSE());
}; };
}
delete $hash->{".kickrunning"};
PT_END; PT_END;
}));
};
Log3 ($hash->{NAME},4,"OWX_ASYNC_PT_Kick".GP_Catch($@)) if ($@);
}
return 1;
} }
######################################################################################## ########################################################################################
@ -950,17 +926,42 @@ sub OWX_ASYNC_Undef ($$) {
# #
######################################################################################## ########################################################################################
sub OWX_ASYNC_Verify ($$) { sub OWX_ASYNC_PT_Verify($) {
my ($hash,$dev) = @_; my ($hash) = @_;
my $address = substr($dev,0,15);
if (OWX_ASYNC_Search($hash)) { #-- get the interface
if (my $owx_devices = OWX_ASYNC_AwaitSearchResponse($hash)) { my $async = $hash->{IODev}->{ASYNC};
if (grep {/$address/} @{$owx_devices}) { my $romid = $hash->{ROM_ID};
return 1;
}; #-- Verify a devices is present on the 1-Wire bus
}; if (defined $async) {
return PT_THREAD(sub {
my ($thread) = @_;
PT_BEGIN($thread);
$thread->{pt_verify} = $async->get_pt_verify($romid);
$thread->{TimeoutTime} = gettimeofday()+2; #TODO: implement attribute-based timeout
PT_WAIT_THREAD($thread->{pt_verify});
delete $thread->{TimeoutTime};
die $thread->{pt_verify}->PT_CAUSE() if ($thread->{pt_verify}->PT_STATE() == PT_ERROR);
my $value = $thread->{pt_verify}->PT_RETVAL();
if( $value == 0 ){
readingsSingleUpdate($hash,"present",0,$hash->{PRESENT});
} else {
readingsSingleUpdate($hash,"present",1,!$hash->{PRESENT});
}
$hash->{PRESENT} = $value;
PT_END;
});
} else {
my $owx_interface = $hash->{IODev}->{INTERFACE};
if( !defined($owx_interface) ) {
die "OWX: Verify called with undefined interface on bus $hash->{IODev}->{NAME}";
} else {
die "OWX: Verify called with unknown interface $owx_interface on bus $hash->{IODev}->{NAME}";
}
} }
return 0;
} }
######################################################################################## ########################################################################################
@ -983,209 +984,171 @@ sub OWX_ASYNC_Verify ($$) {
# #
######################################################################################## ########################################################################################
sub OWX_ASYNC_Execute($$$$$$) { sub OWX_ASYNC_PT_Execute($$$$$) {
my ( $hash, $context, $reset, $owx_dev, $data, $numread ) = @_; my ( $hash, $reset, $owx_dev, $data, $numread ) = @_;
if (my $executor = $hash->{ASYNC}) { if (my $executor = $hash->{ASYNC}) {
delete $context->{ExecuteResponse}; return $executor->get_pt_execute($reset,$owx_dev,$data,$numread);
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 { } else {
return 0; die "OWX_ASYNC_PT_Execute: no async device assigned";
} }
}; }
########################################################################################
#
# OWX_ASYNC_AfterExecute - is called when a query initiated by OWX_Execute successfully returns
#
# calls 'AfterExecuteFn' on the devices module (if such is defined)
# stores data read in $hash->{replies}{$owx_dev}{$context} after calling 'AfterExecuteFn'
#
# Attention: this function is not intendet to be called directly!
#
# Parameter hash = hash of bus master
# context = context parameter of call to OWX_Execute. Allows to correlate request and response
# success = indicates whether an error did occur
# reset = indicates whether a reset was carried out
# owx_dev = 1-wire device-address
# data = data written to the 1-wire device before read was executed
# numread = number of bytes requested from 1-wire device
# readdata = bytes read from 1-wire device
#
# Returns: nothing
#
########################################################################################
sub OWX_ASYNC_AfterExecute($$$$$$$$) {
my ( $master, $context, $success, $reset, $owx_dev, $writedata, $numread, $readdata ) = @_;
Log3 ($master->{NAME},5,"AfterExecute:".
" context: ".(defined $context ? $context : "undef").
", success: ".(defined $success ? $success : "undef").
", reset: ".(defined $reset ? $reset : "undef").
", owx_dev: ".(defined $owx_dev ? $owx_dev : "undef").
", writedata: ".(defined $writedata ? unpack ("H*",$writedata) : "undef").
", numread: ".(defined $numread ? $numread : "undef").
", readdata: ".(defined $readdata ? unpack ("H*",$readdata) : "undef"));
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($$@) { sub OWX_ASYNC_Schedule($$@) {
my ( $hash, $task, @args ) = @_; my ( $hash, $task, @args ) = @_;
my $master = $hash->{IODev}; my $master = $hash->{IODev};
die "OWX_ASYNC_Schedule: Master not Active" unless $master->{STATE} eq "Active"; die "OWX_ASYNC_Schedule: Master not Active" unless $master->{STATE} eq "Active";
my $owx_dev = $hash->{ROM_ID}; my $name = $hash->{NAME};
$task->{ExecuteArgs} = \@args; $task->{ExecuteArgs} = \@args;
my $now = gettimeofday(); $task->{ExecuteTime} = gettimeofday() unless (defined $task->{ExecuteTime});
$task->{ExecuteTime} = $now; if (defined $master->{tasks}->{$name}) {
if (defined $master->{tasks}->{$owx_dev}) { push @{$master->{tasks}->{$name}}, $task;
push @{$master->{tasks}->{$owx_dev}}, $task; $hash->{NUMTASKS} = @{$master->{tasks}->{$name}};
} else { } else {
$master->{tasks}->{$owx_dev} = [$task]; $master->{tasks}->{$name} = [$task];
$hash->{NUMTASKS} = 1;
} }
main::InternalTimer($now, "OWX_ASYNC_RunTasks", $master,0); #TODO make use of $master->{".nexttasktime"}
InternalTimer($task->{ExecuteTime}, "OWX_ASYNC_RunTasks", $master,0);
}; };
sub OWX_ASYNC_ScheduleMaster($$@) { sub OWX_ASYNC_ScheduleMaster($$@) {
my ( $master, $task, @args ) = @_; my ( $master, $task, @args ) = @_;
die "OWX_ASYNC_Schedule: Master not Active" unless $master->{STATE} eq "Active"; die "OWX_ASYNC_Schedule: Master not Active" unless $master->{STATE} eq "Active";
my $name = $master->{NAME};
$task->{ExecuteArgs} = \@args; $task->{ExecuteArgs} = \@args;
my $now = gettimeofday(); $task->{ExecuteTime} = gettimeofday() unless (defined $task->{ExecuteTime});
$task->{ExecuteTime} = $now; if (defined $master->{tasks}->{$name}) {
if (defined $master->{tasks}->{master}) { push @{$master->{tasks}->{$name}}, $task;
push @{$master->{tasks}->{master}}, $task; $master->{NUMTASKS} = @{$master->{tasks}->{$name}};
} else { } else {
$master->{tasks}->{master} = [$task]; $master->{tasks}->{$name} = [$task];
$master->{NUMTASKS} = 1;
} }
main::InternalTimer($now, "OWX_ASYNC_RunTasks", $master,0); #TODO make use of $master->{".nexttasktime"}
InternalTimer($task->{ExecuteTime}, "OWX_ASYNC_RunTasks", $master,0);
}; };
sub OWX_ASYNC_RunToCompletion($$) {
my ($master,$task) = @_;
my $task_state;
do {
OWX_ASYNC_Poll($master);
OWX_ASYNC_RunTasks($master);
$task_state = $task->PT_STATE();
} while ($task_state == PT_INITIAL or $task_state == PT_WAITING or $task_state == PT_YIELDED);
return $task_state;
}
sub OWX_ASYNC_RunTasks($) { sub OWX_ASYNC_RunTasks($) {
my ( $master ) = @_; my ( $master ) = @_;
if ($master->{STATE} eq "Active") { if ($master->{STATE} eq "Active") {
Log3 ($master->{NAME},5,"OWX_ASYNC_RunTasks: ".((defined $master->{".currenttaskdevice"}) ? $master->{".currenttaskdevice"} : "-undefined-")." called") if ($owx_async_debug); Log3 ($master->{NAME},5,"OWX_ASYNC_RunTasks: called") if ($owx_async_debug>2);
my $now = gettimeofday(); my $now = gettimeofday();
my $currentqueue; while(1) {
my $currentdevice = $master->{".currenttaskdevice"}; my @queue_waiting = ();
$currentqueue = $master->{tasks}->{$currentdevice} if (defined $currentdevice); my @queue_ready = ();
do { my @queue_sleeping = ();
unless (defined $currentqueue and @$currentqueue) { my @queue_initial = ();
foreach my $owx_dev (keys %{$master->{tasks}}) { foreach my $name (keys %{$master->{tasks}}) {
my $queue = $master->{tasks}->{$owx_dev}; my $queue = $master->{tasks}->{$name};
if (@$queue) { while (@$queue) {
# if task is eligible to run now: my $state = $queue->[0]->PT_STATE();
if (defined ($queue->[0]->{ExecuteTime}) and ($now >= $queue->[0]->{ExecuteTime})) { if ($state == PT_WAITING) {
$currentqueue = $queue; push @queue_waiting,{ device => $name, queue => $queue};
$currentdevice = $owx_dev;
Log3 ($master->{NAME},5,"OWX_ASYNC_RunTasks: $owx_dev identified") if ($owx_async_debug);
last; last;
} } elsif ($state == PT_YIELDED) {
if ($now >= $queue->[0]->{ExecuteTime}) {
push @queue_ready, { device => $name, queue => $queue};
} else { } else {
delete $master->{tasks}->{$owx_dev}; push @queue_sleeping, { device => $name, queue => $queue};
} }
last;
} elsif ($state == PT_INITIAL) {
push @queue_initial, { device => $name, queue => $queue};
last;
} else {
shift @$queue;
$main::defs{$name}->{NUMTASKS} = @$queue;
} }
}
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: delete $master->{tasks}->{$name} unless (@$queue);
if (!$ret or $@) {
shift @$currentqueue;
undef $currentqueue;
my $msg = ($@) ? GP_Catch($@) : $task->PT_RETVAL();
if (defined $msg) {
Log3 ($master->{NAME},3,"OWX_ASYNC_RunTasks: $currentdevice Error running task: $msg");
} else {
Log3 ($master->{NAME},5,"OWX_ASYNC_RunTasks: $currentdevice finished task");
} }
if (defined (my $current = @queue_waiting ? shift @queue_waiting : @queue_ready ? shift @queue_ready : @queue_initial ? shift @queue_initial : undef)) {
my $task = $current->{queue}->[0];
my $timeout = $task->{TimeoutTime};
if ($task->PT_SCHEDULE(@{$task->{ExecuteArgs}})) {
my $state = $task->PT_STATE();
# waiting for ExecuteResponse: # waiting for ExecuteResponse:
} elsif (defined $task->{TimeoutTime}) { if ($state == PT_WAITING) {
die "$current->{device} unexpected thread state PT_WAITING without TimeoutTime" unless (defined $task->{TimeoutTime});
#task timed out: #task timed out:
if ($now >= $task->{TimeoutTime}) { if ($now >= $task->{TimeoutTime}) {
shift @$currentqueue; Log3 ($master->{NAME},4,"OWX_ASYNC_RunTasks: $current->{device} task timed out");
undef $currentqueue; Log3 ($master->{NAME},5,sprintf("OWX_ASYNC_RunTasks: $current->{device} TimeoutTime: %.6f, now: %.6f",$task->{TimeoutTime},$now)) if ($owx_async_debug>1);
Log3 ($master->{NAME},3,"OWX_ASYNC_RunTasks: $currentdevice task timed out"); $task->PT_CANCEL("Timeout");
Log3 ($master->{NAME},5,sprintf("OWX_ASYNC_RunTasks: $currentdevice TimeoutTime: %.6f, now: %.6f",$task->{TimeoutTime},$now)); shift @{$current->{queue}};
$main::defs{$current->{device}}->{NUMTASKS} = @{$current->{queue}};
next;
} else { } else {
Log3 $master->{NAME},5,"OWX_ASYNC_RunTasks: $currentdevice waiting for data or timeout" if ($owx_async_debug); Log3 $master->{NAME},5,"OWX_ASYNC_RunTasks: $current->{device} waiting for data or timeout" if ($owx_async_debug>2);
#new timeout or timeout did change: #new timeout or timeout did change:
if (!defined $timeout or $timeout != $task->{TimeoutTime}) { if (!defined $timeout or $timeout != $task->{TimeoutTime}) {
Log3 $master->{NAME},5,sprintf("OWX_ASYNC_RunTasks: $currentdevice schedule for timeout at %.6f",$task->{TimeoutTime}); Log3 $master->{NAME},5,sprintf("OWX_ASYNC_RunTasks: $current->{device} schedule for timeout at %.6f",$task->{TimeoutTime});
main::InternalTimer($task->{TimeoutTime}, "OWX_ASYNC_RunTasks", $master,0); InternalTimer($task->{TimeoutTime}, "OWX_ASYNC_RunTasks", $master,0);
} }
last;
} }
# or not finished running, no error but scheduled for future: # sleeping:
} elsif (defined $task->{ExecuteTime} and $now < $task->{ExecuteTime}) { } elsif ($state == PT_YIELDED) {
undef $currentqueue; next;
Log3 ($master->{NAME},5,"OWX_ASYNC_RunTasks: $currentdevice task not finished, next executetime: $task->{ExecuteTime}"); } else {
} elsif ($owx_async_debug) { die "$current->{device} unexpected thread state while running: $state";
Log3 $master->{NAME},5,"OWX_ASYNC_RunTasks: $currentdevice no action";
} }
if (defined $currentqueue and @$currentqueue) { } else {
Log3 $master->{NAME},5,"OWX_ASYNC_RunTasks: $currentdevice exit loop" if ($owx_async_debug); my $state = $task->PT_STATE();
$master->{".currenttaskdevice"} = $currentdevice; if ($state == PT_ENDED) {
OWX_ASYNC_Poll($master); Log3 ($master->{NAME},5,"OWX_ASYNC_RunTasks: $current->{device} finished task");
return; } elsif ($state == PT_EXITED) {
} elsif ($owx_async_debug) { Log3 ($master->{NAME},4,"OWX_ASYNC_RunTasks: $current->{device} exited task: ".(defined $task->PT_RETVAL() ? $task->PT_RETVAL : "- no retval -"));
Log3 $master->{NAME},5,sprintf("OWX_ASYNC_RunTasks: -undefined- continue loop"); } elsif ($state == PT_ERROR) {
Log3 ($master->{NAME},4,"OWX_ASYNC_RunTasks: $current->{device} Error task: ".$task->PT_CAUSE());
$main::defs{$current->{device}}->{PRESENT} = 0;
} else {
die "$current->{device} unexpected thread state after termination: $state";
}
shift @{$current->{queue}};
$main::defs{$current->{device}}->{NUMTASKS} = @{$current->{queue}};
next;
} }
} else { } else {
my $nexttime; my $nexttime;
foreach my $owx_dev (keys %{$master->{tasks}}) { my $nextdevice;
my $queue = $master->{tasks}->{$owx_dev}; foreach my $current (@queue_sleeping) {
if (@$queue) {
my $nexttask = $queue->[0];
# if task is scheduled for future: # if task is scheduled for future:
if (defined $nexttask->{ExecuteTime}) { if (!defined $nexttime or ($nexttime > $current->{queue}->[0]->{ExecuteTime})) {
$nexttime = $nexttask->{ExecuteTime} if (!defined $nexttime or ($nexttime > $nexttask->{ExecuteTime})); $nexttime = $current->{queue}->[0]->{ExecuteTime};
$currentdevice = $owx_dev; $nextdevice = $current->{device};
}
} else {
delete $master->{tasks}->{$owx_dev};
} }
} }
if (defined $nexttime) { if (defined $nexttime) {
if ($nexttime > $now) { if ($nexttime > $now) {
if (!defined $master->{".nexttasktime"} or $nexttime < $master->{".nexttasktime"} or $now >= $master->{".nexttasktime"}) { 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); Log3 $master->{NAME},5,sprintf("OWX_ASYNC_RunTasks: $nextdevice schedule next at %.6f",$nexttime) if ($owx_async_debug);
main::InternalTimer($nexttime, "OWX_ASYNC_RunTasks", $master,0); main::InternalTimer($nexttime, "OWX_ASYNC_RunTasks", $master,0);
$master->{".nexttasktime"} = $nexttime; $master->{".nexttasktime"} = $nexttime;
} else { } else {
Log3 $master->{NAME},5,sprintf("OWX_ASYNC_RunTasks: $currentdevice skip %.6f, allready scheduled at %.6f",$nexttime,$master->{".nexttasktime"}) if ($owx_async_debug); Log3 $master->{NAME},5,sprintf("OWX_ASYNC_RunTasks: $nextdevice skip %.6f, allready scheduled at %.6f",$nexttime,$master->{".nexttasktime"}) if ($owx_async_debug>2);
} }
} else { } else {
delete $master->{".nexttasktime"}; Log3 $master->{NAME},5,sprintf("OWX_ASYNC_RunTasks: $nextdevice nexttime at %.6f allready passed",$nexttime) if ($owx_async_debug>2);
Log3 $master->{NAME},5,sprintf("OWX_ASYNC_RunTasks: $currentdevice nexttime at %.6f allready passed",$nexttime) if ($owx_async_debug);
} }
} else { } else {
Log3 $master->{NAME},5,sprintf("OWX_ASYNC_RunTasks: -undefined- no nexttime") if ($owx_async_debug); Log3 $master->{NAME},5,sprintf("OWX_ASYNC_RunTasks: -undefined- no nexttime") if ($owx_async_debug>2);
} }
delete $master->{".currenttaskdevice"}; Log3 $master->{NAME},5,sprintf("OWX_ASYNC_RunTasks: -undefined- exit loop") if ($owx_async_debug>2);
Log3 $master->{NAME},5,sprintf("OWX_ASYNC_RunTasks: -undefined- exit loop") if ($owx_async_debug); last;
OWX_ASYNC_Poll($master);
return;
} }
} while (1); };
} }
}; };

View File

@ -75,7 +75,7 @@ use vars qw{%attr %defs %modules $readingFnAttributes $init_done};
use strict; use strict;
use warnings; use warnings;
use GPUtils qw(:all); use GPUtils qw(:all);
use Time::HiRes qw( gettimeofday tv_interval usleep ); use Time::HiRes qw( gettimeofday );
#add FHEM/lib to @INC if it's not allready included. Should rather be in fhem.pl than here though... #add FHEM/lib to @INC if it's not allready included. Should rather be in fhem.pl than here though...
BEGIN { BEGIN {
@ -90,7 +90,7 @@ use ProtoThreads;
no warnings 'deprecated'; no warnings 'deprecated';
sub Log($$); sub Log($$);
my $owx_version="5.15"; my $owx_version="5.16";
#-- fixed raw channel name, flexible channel name #-- fixed raw channel name, flexible channel name
my @owg_fixed = ("A","B","C","D"); my @owg_fixed = ("A","B","C","D");
my @owg_channel = ("A","B","C","D"); my @owg_channel = ("A","B","C","D");
@ -157,6 +157,8 @@ sub OWAD_Initialize ($) {
$hash->{UndefFn} = "OWAD_Undef"; $hash->{UndefFn} = "OWAD_Undef";
$hash->{GetFn} = "OWAD_Get"; $hash->{GetFn} = "OWAD_Get";
$hash->{SetFn} = "OWAD_Set"; $hash->{SetFn} = "OWAD_Set";
$hash->{NotifyFn}= "OWAD_Notify";
$hash->{InitFn} = "OWAD_Init";
$hash->{AttrFn} = "OWAD_Attr"; $hash->{AttrFn} = "OWAD_Attr";
my $attlist = "IODev do_not_notify:0,1 showtime:0,1 model:DS2450 loglevel:0,1,2,3,4,5 ". my $attlist = "IODev do_not_notify:0,1 showtime:0,1 model:DS2450 loglevel:0,1,2,3,4,5 ".
@ -276,12 +278,27 @@ sub OWAD_Define ($$) {
readingsSingleUpdate($hash,"state","defined",1); readingsSingleUpdate($hash,"state","defined",1);
Log 3, "OWAD: Device $name defined."; Log 3, "OWAD: Device $name defined.";
#-- Initialization reading according to interface type $hash->{NOTIFYDEV} = "global";
my $interface= $hash->{IODev}->{TYPE};
if ($init_done) {
OWAD_Init($hash);
}
return undef;
}
sub OWAD_Notify ($$) {
my ($hash,$dev) = @_;
if( grep(m/^(INITIALIZED|REREADCFG)$/, @{$dev->{CHANGED}}) ) {
OWAD_Init($hash);
} elsif( grep(m/^SAVE$/, @{$dev->{CHANGED}}) ) {
}
}
sub OWAD_Init ($) {
my ($hash)=@_;
#-- Start timer for updates #-- Start timer for updates
InternalTimer(time()+60, "OWAD_GetValues", $hash, 0); RemoveInternalTimer($hash);
InternalTimer(gettimeofday()+10, "OWAD_InitializeDevice", $hash, 0);
return undef; return undef;
} }
@ -326,6 +343,9 @@ sub OWAD_Attr(@) {
AssignIoPort($hash,$value); AssignIoPort($hash,$value);
if( defined($hash->{IODev}) ) { if( defined($hash->{IODev}) ) {
$hash->{ASYNC} = $hash->{IODev}->{TYPE} eq "OWX_ASYNC" ? 1 : 0; $hash->{ASYNC} = $hash->{IODev}->{TYPE} eq "OWX_ASYNC" ? 1 : 0;
if ($init_done) {
OWAD_Init($hash);
}
} }
last; last;
}; };
@ -565,11 +585,17 @@ sub OWAD_Get($@) {
#-- get present #-- get present
if($a[1] eq "present") { if($a[1] eq "present") {
#-- hash of the busmaster
my $master = $hash->{IODev};
#-- asynchronous mode #-- asynchronous mode
if( $hash->{ASYNC} ){ if( $hash->{ASYNC} ){
$value = OWX_ASYNC_Verify($master,$hash->{ROM_ID}); my ($task,$task_state);
eval {
$task = OWX_ASYNC_PT_Verify($hash);
OWX_ASYNC_Schedule($hash,$task);
$task_state = OWX_ASYNC_RunToCompletion($master,$task);
};
return GP_Catch($@) if $@;
return $task->PT_CAUSE() if ($task_state == PT_ERROR or $task_state == PT_CANCELED);
return "$name.present => ".ReadingsVal($name,"present","unknown");
} else { } else {
$value = OWX_Verify($master,$hash->{ROM_ID}); $value = OWX_Verify($master,$hash->{ROM_ID});
} }
@ -595,12 +621,13 @@ sub OWAD_Get($@) {
if( $interface eq "OWX" ){ if( $interface eq "OWX" ){
$ret = OWXAD_GetPage($hash,"reading",1); $ret = OWXAD_GetPage($hash,"reading",1);
}elsif( $interface eq "OWX_ASYNC" ){ }elsif( $interface eq "OWX_ASYNC" ){
#TODO use OWX_ASYNC_Schedule instead my ($task,$task_state);
my $task = PT_THREAD(\&OWXAD_PT_GetPage);
eval { eval {
while ($task->PT_SCHEDULE($hash,"reading",1)) { OWX_ASYNC_Poll($hash->{IODev}); }; $task = OWXAD_PT_GetPage($hash,"reading",1);
OWX_ASYNC_Schedule($hash,$task);
$task_state = OWX_ASYNC_RunToCompletion($master,$task);
}; };
$ret = ($@) ? GP_Catch($@) : $task->PT_RETVAL(); $ret = ($@) ? GP_Catch($@) : ($task_state == PT_ERROR or $task_state == PT_CANCELED) ? $task->PT_CAUSE() : $task->PT_RETVAL();
#-- OWFS interface #-- OWFS interface
}elsif( $interface eq "OWServer" ){ }elsif( $interface eq "OWServer" ){
$ret = OWFSAD_GetPage($hash,"reading",1); $ret = OWFSAD_GetPage($hash,"reading",1);
@ -626,12 +653,13 @@ sub OWAD_Get($@) {
if( $interface eq "OWX" ){ if( $interface eq "OWX" ){
$ret = OWXAD_GetPage($hash,"alarm",1); $ret = OWXAD_GetPage($hash,"alarm",1);
}elsif( $interface eq "OWX_ASYNC" ){ }elsif( $interface eq "OWX_ASYNC" ){
#TODO use OWX_ASYNC_Schedule instead my ($task,$task_state);
my $task = PT_THREAD(\&OWXAD_PT_GetPage);
eval { eval {
while ($task->PT_SCHEDULE($hash,"alarm",1)) { OWX_ASYNC_Poll($hash->{IODev}); }; $task = OWXAD_PT_GetPage($hash,"alarm",1);
OWX_ASYNC_Schedule($hash,$task);
$task_state = OWX_ASYNC_RunToCompletion($master,$task);
}; };
$ret = ($@) ? GP_Catch($@) : $task->PT_RETVAL(); $ret = ($@) ? GP_Catch($@) : ($task_state == PT_ERROR or $task_state == PT_CANCELED) ? $task->PT_CAUSE() : $task->PT_RETVAL();
#-- OWFS interface #-- OWFS interface
}elsif( $interface eq "OWServer" ){ }elsif( $interface eq "OWServer" ){
$ret = OWFSAD_GetPage($hash,"alarm",1); $ret = OWFSAD_GetPage($hash,"alarm",1);
@ -665,12 +693,13 @@ sub OWAD_Get($@) {
if( $interface eq "OWX" ){ if( $interface eq "OWX" ){
$ret = OWXAD_GetPage($hash,"status",1); $ret = OWXAD_GetPage($hash,"status",1);
}elsif( $interface eq "OWX_ASYNC" ){ }elsif( $interface eq "OWX_ASYNC" ){
#TODO use OWX_ASYNC_Schedule instead my ($task,$task_state);
my $task = PT_THREAD(\&OWXAD_PT_GetPage);
eval { eval {
while ($task->PT_SCHEDULE($hash,"status",1)) { OWX_ASYNC_Poll($hash->{IODev}); }; $task = OWXAD_PT_GetPage($hash,"status",1);
OWX_ASYNC_Schedule($hash,$task);
$task_state = OWX_ASYNC_RunToCompletion($master,$task);
}; };
$ret = ($@) ? GP_Catch($@) : $task->PT_RETVAL(); $ret = ($@) ? GP_Catch($@) : ($task_state == PT_ERROR or $task_state == PT_CANCELED) ? $task->PT_CAUSE() : $task->PT_RETVAL();
#-- OWFS interface #-- OWFS interface
}elsif( $interface eq "OWServer" ){ }elsif( $interface eq "OWServer" ){
$ret = OWFSAD_GetPage($hash,"status",1); $ret = OWFSAD_GetPage($hash,"status",1);
@ -741,10 +770,6 @@ sub OWAD_GetValues($) {
my $ret = ""; my $ret = "";
my ($ret1,$ret2,$ret3); my ($ret1,$ret2,$ret3);
#-- check if device needs to be initialized
OWAD_InitializeDevice($hash)
if( $hash->{READINGS}{"state"}{VAL} eq "defined");
#-- define warnings #-- define warnings
my $warn = "none"; my $warn = "none";
$hash->{ALARM} = "0"; $hash->{ALARM} = "0";
@ -763,9 +788,9 @@ sub OWAD_GetValues($) {
#} #}
}elsif( $interface eq "OWX_ASYNC" ){ }elsif( $interface eq "OWX_ASYNC" ){
eval { eval {
OWX_ASYNC_Schedule( $hash, PT_THREAD(\&OWXAD_PT_GetPage),$hash,"reading",0 ); OWX_ASYNC_Schedule( $hash, OWXAD_PT_GetPage($hash,"reading",0));
OWX_ASYNC_Schedule( $hash, PT_THREAD(\&OWXAD_PT_GetPage),$hash,"alarm",0 ); OWX_ASYNC_Schedule( $hash, OWXAD_PT_GetPage($hash,"alarm",0));
OWX_ASYNC_Schedule( $hash, PT_THREAD(\&OWXAD_PT_GetPage),$hash,"status",1 ); OWX_ASYNC_Schedule( $hash, OWXAD_PT_GetPage($hash,"status",1));
}; };
$ret .= GP_Catch($@) if $@; $ret .= GP_Catch($@) if $@;
}elsif( $interface eq "OWServer" ){ }elsif( $interface eq "OWServer" ){
@ -859,8 +884,8 @@ sub OWAD_InitializeDevice($) {
$ret2 = OWXAD_SetPage($hash,"alarm"); $ret2 = OWXAD_SetPage($hash,"alarm");
}elsif( $interface eq "OWX_ASYNC" ){ }elsif( $interface eq "OWX_ASYNC" ){
eval { eval {
OWX_ASYNC_Schedule( $hash, PT_THREAD(\&OWXAD_PT_SetPage),$hash,"status" ); OWX_ASYNC_Schedule( $hash, OWXAD_PT_SetPage($hash,"status"));
OWX_ASYNC_Schedule( $hash, PT_THREAD(\&OWXAD_PT_SetPage),$hash,"alarm" ); OWX_ASYNC_Schedule( $hash, OWXAD_PT_SetPage($hash,"alarm"));
}; };
$ret .= GP_Catch($@) if $@; $ret .= GP_Catch($@) if $@;
#-- OWFS interface #-- OWFS interface
@ -880,7 +905,7 @@ sub OWAD_InitializeDevice($) {
#-- Set state to initialized #-- Set state to initialized
readingsSingleUpdate($hash,"state","initialized",1); readingsSingleUpdate($hash,"state","initialized",1);
return undef; return OWAD_GetValues($hash);
} }
####################################################################################### #######################################################################################
@ -982,7 +1007,7 @@ sub OWAD_Set($@) {
$ret = OWXAD_SetPage($hash,"status"); $ret = OWXAD_SetPage($hash,"status");
}elsif( $interface eq "OWX_ASYNC" ){ }elsif( $interface eq "OWX_ASYNC" ){
eval { eval {
OWX_ASYNC_Schedule( $hash, PT_THREAD(\&OWXAD_PT_SetPage),$hash,"status" ); OWX_ASYNC_Schedule( $hash, OWXAD_PT_SetPage($hash,"status"));
}; };
$ret = GP_Catch($@) if $@; $ret = GP_Catch($@) if $@;
#-- OWFS interface #-- OWFS interface
@ -1033,7 +1058,7 @@ sub OWAD_Set($@) {
$ret = OWXAD_SetPage($hash,"alarm"); $ret = OWXAD_SetPage($hash,"alarm");
}elsif( $interface eq "OWX_ASYNC" ){ }elsif( $interface eq "OWX_ASYNC" ){
eval { eval {
OWX_ASYNC_Schedule( $hash, PT_THREAD(\&OWXAD_PT_SetPage),$hash,"status" ); OWX_ASYNC_Schedule( $hash, OWXAD_PT_SetPage($hash,"status"));
}; };
$ret = GP_Catch($@) if $@; $ret = GP_Catch($@) if $@;
#-- OWFS interface #-- OWFS interface
@ -1537,9 +1562,13 @@ sub OWXAD_SetPage($$) {
sub OWXAD_PT_GetPage($$$) { sub OWXAD_PT_GetPage($$$) {
my ($thread,$hash,$page,$final) = @_; my ($hash,$page,$final) = @_;
my ($select, $res, $res2, $res3, @data, $an, $vn); return PT_THREAD(sub {
my ($thread) = @_;
my ($res, $res2, $res3, @data, $an, $vn);
#-- ID of the device, hash of the busmaster #-- ID of the device, hash of the busmaster
my $owx_dev = $hash->{ROM_ID}; my $owx_dev = $hash->{ROM_ID};
@ -1549,50 +1578,51 @@ sub OWXAD_PT_GetPage($$$) {
PT_BEGIN($thread); PT_BEGIN($thread);
#-- reset presence
$hash->{PRESENT} = 0;
#=============== get the voltage reading =============================== #=============== get the voltage reading ===============================
if( $page eq "reading") { if( $page eq "reading") {
#-- issue the match ROM command \x55 and the start conversion command #-- issue the match ROM command \x55 and the start conversion command
unless (OWX_ASYNC_Execute( $master, $thread, 1, $owx_dev, "\x3C\x0F\x00\xFF\xFF", 0 )) {
PT_EXIT("$owx_dev not accessible for conversion"); $thread->{pt_execute} = OWX_ASYNC_PT_Execute($master,1,$owx_dev, "\x3C\x0F\x00\xFF\xFF", 0 );
} $thread->{ExecuteTime} = gettimeofday() + 0.05; # was 0.02
PT_WAIT_UNTIL(defined $thread->{ExecuteResponse}); $thread->{TimeoutTime} = gettimeofday()+2; #TODO: implement attribute-based timeout
#TODO async 20ms delay PT_WAIT_THREAD($thread->{pt_execute});
select(undef,undef,undef,0.02); delete $thread->{TimeoutTime};
die $thread->{pt_execute}->PT_CAUSE() if ($thread->{pt_execute}->PT_STATE() == PT_ERROR);
PT_YIELD_UNTIL(gettimeofday() >= $thread->{ExecuteTime});
delete $thread->{ExecuteTime};
#-- issue the match ROM command \x55 and the read conversion page command #-- issue the match ROM command \x55 and the read conversion page command
# \xAA\x00\x00 # \xAA\x00\x00
$select="\xAA\x00\x00"; $thread->{'select'}="\xAA\x00\x00";
#=============== get the alarm reading =============================== #=============== get the alarm reading ===============================
} elsif ( $page eq "alarm" ) { } elsif ( $page eq "alarm" ) {
#-- issue the match ROM command \x55 and the read alarm page command #-- issue the match ROM command \x55 and the read alarm page command
# \xAA\x10\x00 # \xAA\x10\x00
$select="\xAA\x10\x00"; $thread->{'select'}="\xAA\x10\x00";
#=============== get the status reading =============================== #=============== get the status reading ===============================
} elsif ( $page eq "status" ) { } elsif ( $page eq "status" ) {
#-- issue the match ROM command \x55 and the read status memory page command #-- issue the match ROM command \x55 and the read status memory page command
# \xAA\x08\x00 r # \xAA\x08\x00 r
$select="\xAA\x08\x00"; $thread->{'select'}="\xAA\x08\x00";
#=============== wrong value requested =============================== #=============== wrong value requested ===============================
} else { } else {
return "wrong memory page requested from $owx_dev"; die "wrong memory page requested from $owx_dev";
} }
#-- reading 9 + 3 + 8 data bytes and 2 CRC bytes = 22 bytes #-- reading 9 + 3 + 8 data bytes and 2 CRC bytes = 22 bytes
unless (OWX_ASYNC_Execute( $master, $thread, 1, $owx_dev, $select, 10 )) {
PT_EXIT("$owx_dev not accessible in reading $page page"); $thread->{pt_execute} = OWX_ASYNC_PT_Execute($master,1,$owx_dev, $thread->{'select'}, 10 );
} $thread->{TimeoutTime} = gettimeofday()+2; #TODO: implement attribute-based timeout
PT_WAIT_UNTIL(defined $thread->{ExecuteResponse}); PT_WAIT_THREAD($thread->{pt_execute});
my $response = $thread->{ExecuteResponse}; delete $thread->{TimeoutTime};
unless ($response->{success}) { die $thread->{pt_execute}->PT_CAUSE() if ($thread->{pt_execute}->PT_STATE() == PT_ERROR);
PT_EXIT("$owx_dev read not successful"); my $response = $thread->{pt_execute}->PT_RETVAL();
} my $res = OWXAD_BinValues($hash,"ds2450.get".$page.($final ? ".final" : ""),1,1,$owx_dev,$thread->{'select'},10,$response);
my $res = OWXAD_BinValues($hash,"ds2450.get".$page.($final ? ".final" : ""),1,1,$owx_dev,$response->{writedata},$response->{numread},$response->{readdata});
if ($res) { if ($res) {
PT_EXIT($res); die $res;
} }
PT_END; PT_END;
});
} }
######################################################################################## ########################################################################################
@ -1606,8 +1636,11 @@ sub OWXAD_PT_GetPage($$$) {
sub OWXAD_PT_SetPage($$) { sub OWXAD_PT_SetPage($$) {
my ($thread,$hash,$page) = @_; my ($hash,$page) = @_;
return PT_THREAD(sub {
my ($thread) = @_;
my ($select, $res, $res2, $res3, @data); my ($select, $res, $res2, $res3, @data);
#-- ID of the device, hash of the busmaster #-- ID of the device, hash of the busmaster
@ -1628,8 +1661,8 @@ sub OWXAD_PT_SetPage($$) {
$select .= sprintf "%c\xFF\xFF\xFF",int($hash->{owg_vhigh}->[$i]*256000/$owg_range[$i]); $select .= sprintf "%c\xFF\xFF\xFF",int($hash->{owg_vhigh}->[$i]*256000/$owg_range[$i]);
} }
#++Use of uninitialized value within @owg_vlow in multiplication at #++Use of uninitialized value within @owg_vlow in multiplication at
#++/usr/share/fhem/FHEM/21_OWAD.pm line 1362. #++/usr/share/fhem/FHEM/21_OWAD.pm line 1362.
#=============== set the status =============================== #=============== set the status ===============================
} elsif ( $page eq "status" ) { } elsif ( $page eq "status" ) {
my ($sb1,$sb2)=(0,0); my ($sb1,$sb2)=(0,0);
@ -1663,15 +1696,13 @@ sub OWXAD_PT_SetPage($$) {
PT_EXIT("wrong memory page write attempt"); PT_EXIT("wrong memory page write attempt");
} }
#"setpage" #"setpage"
unless (OWX_ASYNC_Execute( $master, $thread, 1, $owx_dev, $select, 0 )) { $thread->{pt_execute} = OWX_ASYNC_PT_Execute($master,1,$owx_dev, $select, 0 );
PT_EXIT("device $owx_dev not accessible for writing"); $thread->{TimeoutTime} = gettimeofday()+2; #TODO: implement attribute-based timeout
} PT_WAIT_THREAD($thread->{pt_execute});
PT_WAIT_UNTIL(defined $thread->{ExecuteResponse}); delete $thread->{TimeoutTime};
my $response = $thread->{ExecuteResponse}; die $thread->{pt_execute}->PT_CAUSE() if ($thread->{pt_execute}->PT_STATE() == PT_ERROR);
unless ($response->{success}) {
PT_EXIT("$owx_dev write not successful");
}
PT_END; PT_END;
});
} }
1; 1;

View File

@ -99,7 +99,7 @@ no warnings 'deprecated';
sub Log3($$$); sub Log3($$$);
my $owx_version="5.22"; my $owx_version="5.23";
#-- fixed raw channel name, flexible channel name #-- fixed raw channel name, flexible channel name
my @owg_fixed = ("A","B"); my @owg_fixed = ("A","B");
my @owg_channel = ("A","B"); my @owg_channel = ("A","B");
@ -151,6 +151,8 @@ sub OWCOUNT_Initialize ($) {
$hash->{UndefFn} = "OWCOUNT_Undef"; $hash->{UndefFn} = "OWCOUNT_Undef";
$hash->{GetFn} = "OWCOUNT_Get"; $hash->{GetFn} = "OWCOUNT_Get";
$hash->{SetFn} = "OWCOUNT_Set"; $hash->{SetFn} = "OWCOUNT_Set";
$hash->{NotifyFn}= "OWCOUNT_Notify";
$hash->{InitFn} = "OWCOUNT_Init";
$hash->{AttrFn} = "OWCOUNT_Attr"; $hash->{AttrFn} = "OWCOUNT_Attr";
#-- see header for attributes #-- see header for attributes
my $attlist = "IODev do_not_notify:0,1 showtime:0,1 model:DS2423,DS2423enew,DS2423eold LogM LogY ". my $attlist = "IODev do_not_notify:0,1 showtime:0,1 model:DS2423,DS2423enew,DS2423eold LogM LogY ".
@ -264,9 +266,29 @@ sub OWCOUNT_Define ($$) {
readingsSingleUpdate($hash,"state","defined",1); readingsSingleUpdate($hash,"state","defined",1);
Log3 $name, 3, "OWCOUNT: Device $name defined."; Log3 $name, 3, "OWCOUNT: Device $name defined.";
#-- Start timer for updates $hash->{NOTIFYDEV} = "global";
InternalTimer(time()+10, "OWCOUNT_GetValues", $hash, 0);
if ($init_done) {
OWCOUNT_Init($hash);
}
return undef;
}
sub OWCOUNT_Notify ($$) {
my ($hash,$dev) = @_;
if( grep(m/^(INITIALIZED|REREADCFG)$/, @{$dev->{CHANGED}}) ) {
OWCOUNT_Init($hash);
} elsif( grep(m/^SAVE$/, @{$dev->{CHANGED}}) ) {
}
}
sub OWCOUNT_Init ($) {
my ($hash)=@_;
#-- Start timer for updates
RemoveInternalTimer($hash);
InternalTimer(gettimeofday()+10, "OWCOUNT_GetValues", $hash, 0);
#--
readingsSingleUpdate($hash,"state","Initialized",1);
return undef; return undef;
} }
@ -303,6 +325,9 @@ sub OWCOUNT_Attr(@) {
AssignIoPort($hash,$value); AssignIoPort($hash,$value);
if( defined($hash->{IODev}) ) { if( defined($hash->{IODev}) ) {
$hash->{ASYNC} = $hash->{IODev}->{TYPE} eq "OWX_ASYNC" ? 1 : 0; $hash->{ASYNC} = $hash->{IODev}->{TYPE} eq "OWX_ASYNC" ? 1 : 0;
if ($init_done) {
OWCOUNT_Init($hash);
}
} }
last; last;
}; };
@ -626,7 +651,15 @@ sub OWCOUNT_Get($@) {
my $master = $hash->{IODev}; my $master = $hash->{IODev};
#-- asynchronous mode #-- asynchronous mode
if( $hash->{ASYNC} ){ if( $hash->{ASYNC} ){
$value = OWX_ASYNC_Verify($master,$hash->{ROM_ID}); my ($task,$task_state);
eval {
$task = OWX_ASYNC_PT_Verify($hash);
OWX_ASYNC_Schedule($hash,$task);
$task_state = OWX_ASYNC_RunToCompletion($master,$task);
};
return GP_Catch($@) if $@;
return $task->PT_CAUSE() if ($task_state == PT_ERROR or $task_state == PT_CANCELED);
return "$name.present => ".ReadingsVal($name,"present","unknown");
} else { } else {
$value = OWX_Verify($master,$hash->{ROM_ID}); $value = OWX_Verify($master,$hash->{ROM_ID});
} }
@ -800,6 +833,7 @@ sub OWCOUNT_GetPage ($$$@) {
my ($hash, $page,$final,$sync) = @_; my ($hash, $page,$final,$sync) = @_;
#-- get memory page/counter according to interface type #-- get memory page/counter according to interface type
my $master= $hash->{IODev};
my $interface= $hash->{IODev}->{TYPE}; my $interface= $hash->{IODev}->{TYPE};
my $name = $hash->{NAME}; my $name = $hash->{NAME};
my $ret; my $ret;
@ -815,15 +849,16 @@ sub OWCOUNT_GetPage ($$$@) {
$ret = OWXCOUNT_GetPage($hash,$page,$final); $ret = OWXCOUNT_GetPage($hash,$page,$final);
}elsif( $interface eq "OWX_ASYNC" ){ }elsif( $interface eq "OWX_ASYNC" ){
if ($sync) { if ($sync) {
#TODO use OWX_ASYNC_Schedule instead my ($task,$task_state);
my $task = PT_THREAD(\&OWXCOUNT_PT_GetPage);
eval { eval {
while ($task->PT_SCHEDULE($hash,$page,$final)) { OWX_ASYNC_Poll($hash->{IODev}); }; $task = OWXCOUNT_PT_GetPage($hash,$page,$final);
OWX_ASYNC_Schedule($hash,$task);
$task_state = OWX_ASYNC_RunToCompletion($master,$task);
}; };
$ret = ($@) ? GP_Catch($@) : $task->PT_RETVAL(); $ret = ($@) ? GP_Catch($@) : ($task_state == PT_ERROR or $task_state == PT_CANCELED) ? $task->PT_CAUSE() : $task->PT_RETVAL();
} else { } else {
eval { eval {
OWX_ASYNC_Schedule( $hash, PT_THREAD(\&OWXCOUNT_PT_GetPage),$hash,$page,$final ); OWX_ASYNC_Schedule( $hash, OWXCOUNT_PT_GetPage($hash,$page,$final) );
}; };
$ret = GP_Catch($@) if $@; $ret = GP_Catch($@) if $@;
} }
@ -1097,6 +1132,7 @@ sub OWCOUNT_InitializeDevice($) {
my $name = $hash->{NAME}; my $name = $hash->{NAME};
#-- get memory page/counter according to interface type #-- get memory page/counter according to interface type
my $master= $hash->{IODev};
my $interface= $hash->{IODev}->{TYPE}; my $interface= $hash->{IODev}->{TYPE};
my $olddata = ""; my $olddata = "";
@ -1123,12 +1159,13 @@ sub OWCOUNT_InitializeDevice($) {
$ret = OWXCOUNT_GetPage($hash,14,0); $ret = OWXCOUNT_GetPage($hash,14,0);
$ret = OWXCOUNT_SetPage($hash,14,$olddata); $ret = OWXCOUNT_SetPage($hash,14,$olddata);
}elsif( $interface eq "OWX_ASYNC" ){ }elsif( $interface eq "OWX_ASYNC" ){
#TODO use OWX_ASYNC_Schedule instead my ($task,$task_state);
my $task = PT_THREAD(\&OWXCOUNT_PT_InitializeDevicePage);
eval { eval {
while ($task->PT_SCHEDULE($hash,14,$newdata)) { OWX_ASYNC_Poll($hash->{IODev}); }; $task = OWXCOUNT_PT_InitializeDevicePage($hash,14,$newdata);
OWX_ASYNC_Schedule($hash,$task);
$task_state = OWX_ASYNC_RunToCompletion($master,$task);
}; };
$ret = ($@) ? GP_Catch($@) : $task->PT_RETVAL(); $ret = ($@) ? GP_Catch($@) : ($task_state == PT_ERROR or $task_state == PT_CANCELED) ? $task->PT_CAUSE() : $task->PT_RETVAL();
#-- OWFS interface #-- OWFS interface
}elsif( $interface eq "OWServer" ){ }elsif( $interface eq "OWServer" ){
$ret = OWFSCOUNT_GetPage($hash,14,0); $ret = OWFSCOUNT_GetPage($hash,14,0);
@ -1150,12 +1187,13 @@ sub OWCOUNT_InitializeDevice($) {
$ret = OWXCOUNT_GetPage($hash,0,0); $ret = OWXCOUNT_GetPage($hash,0,0);
$ret = OWXCOUNT_SetPage($hash,0,$olddata); $ret = OWXCOUNT_SetPage($hash,0,$olddata);
}elsif( $interface eq "OWX_ASYNC" ){ }elsif( $interface eq "OWX_ASYNC" ){
#TODO use OWX_ASYNC_Schedule instead my ($task,$task_state);
my $task = PT_THREAD(\&OWXCOUNT_PT_InitializeDevicePage);
eval { eval {
while ($task->PT_SCHEDULE($hash,0,$newdata)) { OWX_ASYNC_Poll($hash->{IODev}); }; $task = OWXCOUNT_PT_InitializeDevicePage($hash,0,$newdata);
OWX_ASYNC_Schedule($hash,$task);
$task_state = OWX_ASYNC_RunToCompletion($master,$task);
}; };
$ret = ($@) ? GP_Catch($@) : $task->PT_RETVAL(); $ret = ($@) ? GP_Catch($@) : ($task_state == PT_ERROR or $task_state == PT_CANCELED) ? $task->PT_CAUSE() : $task->PT_RETVAL();
#-- OWFS interface #-- OWFS interface
}elsif( $interface eq "OWServer" ){ }elsif( $interface eq "OWServer" ){
$ret = OWFSCOUNT_GetPage($hash,0,0); $ret = OWFSCOUNT_GetPage($hash,0,0);
@ -1372,7 +1410,7 @@ sub OWCOUNT_SetPage ($$$) {
$ret = OWXCOUNT_SetPage($hash,$page,$data); $ret = OWXCOUNT_SetPage($hash,$page,$data);
}elsif( $interface eq "OWX_ASYNC" ){ }elsif( $interface eq "OWX_ASYNC" ){
eval { eval {
OWX_ASYNC_Schedule( $hash, PT_THREAD(\&OWXCOUNT_PT_SetPage),$hash,$page,$data ); OWX_ASYNC_Schedule( $hash, OWXCOUNT_PT_SetPage($hash,$page,$data) );
}; };
$ret = GP_Catch($@) if $@; $ret = GP_Catch($@) if $@;
#-- OWFS interface #-- OWFS interface
@ -1578,12 +1616,12 @@ sub OWFSCOUNT_SetPage($$$) {
# #
######################################################################################## ########################################################################################
sub OWXCOUNT_BinValues($$$$$$$$) { sub OWXCOUNT_BinValues($$$$$) {
my ($hash, $context, $success, $reset, $owx_dev, $select, $numread, $res) = @_; my ($hash, $context, $owx_dev, $select, $res) = @_;
#-- unused are success, reset, data #-- unused are success, reset, data
return undef unless ($success and defined $context and $context =~ /^(get|set)page\.([\d]+)(\.final|)$/); return undef unless (defined $context and $context =~ /^(get|set)page\.([\d]+)(\.final|)$/);
my $cmd = $1; my $cmd = $1;
my $page = $2; my $page = $2;
@ -1711,7 +1749,7 @@ sub OWXCOUNT_GetPage($$$) {
if( $res eq 0 ); if( $res eq 0 );
return "$owx_dev has returned invalid data" return "$owx_dev has returned invalid data"
if( length($res)!=54); if( length($res)!=54);
return OWXCOUNT_BinValues($hash,$context,1,1,$owx_dev,$select,42,substr($res,12)); return OWXCOUNT_BinValues($hash,$context,$owx_dev,$select,substr($res,12));
} }
######################################################################################## ########################################################################################
@ -1822,9 +1860,11 @@ sub OWXCOUNT_SetPage($$$) {
######################################################################################## ########################################################################################
sub OWXCOUNT_PT_GetPage($$$) { sub OWXCOUNT_PT_GetPage($$$) {
my ($thread,$hash,$page,$final) = @_;
my ($select, $res, $response); my ($hash,$page,$final) = @_;
return PT_THREAD(sub {
my ($thread) = @_;
#-- ID of the device, hash of the busmaster #-- ID of the device, hash of the busmaster
my $owx_dev = $hash->{ROM_ID}; my $owx_dev = $hash->{ROM_ID};
@ -1832,44 +1872,38 @@ sub OWXCOUNT_PT_GetPage($$$) {
PT_BEGIN($thread); PT_BEGIN($thread);
#-- reset presence
$hash->{PRESENT} = 0;
#=============== wrong value requested =============================== #=============== wrong value requested ===============================
if( ($page<0) || ($page>15) ){ if( ($page<0) || ($page>15) ){
PT_EXIT("wrong memory page requested"); die("wrong memory page requested");
} }
#=============== get memory + counter =============================== #=============== get memory + counter ===============================
#-- issue the match ROM command \x55 and the read memory + counter command #-- issue the match ROM command \x55 and the read memory + counter command
# \xA5 TA1 TA2 reading 40 data bytes and 2 CRC bytes # \xA5 TA1 TA2 reading 40 data bytes and 2 CRC bytes
my $ta2 = ($page*32) >> 8; my $ta2 = ($page*32) >> 8;
my $ta1 = ($page*32) & 255; my $ta1 = ($page*32) & 255;
$select=sprintf("\xA5%c%c",$ta1,$ta2); $thread->{'select'}=sprintf("\xA5%c%c",$ta1,$ta2);
#-- reading 9 + 3 + 40 data bytes (32 byte memory, 4 byte counter + 4 byte zeroes) and 2 CRC bytes = 54 bytes #-- reading 9 + 3 + 40 data bytes (32 byte memory, 4 byte counter + 4 byte zeroes) and 2 CRC bytes = 54 bytes
unless (OWX_ASYNC_Execute( $master, $thread, 1, $owx_dev, $select, 42 )) {
PT_EXIT("device $owx_dev not accessible for reading page $page"); $thread->{pt_execute} = OWX_ASYNC_PT_Execute($master,1,$owx_dev, $thread->{'select'}, 42 );
} $thread->{TimeoutTime} = gettimeofday()+2; #TODO: implement attribute-based timeout
PT_WAIT_UNTIL($thread->{ExecuteResponse}); PT_WAIT_THREAD($thread->{pt_execute});
$response = $thread->{ExecuteResponse}; delete $thread->{TimeoutTime};
die $thread->{pt_execute}->PT_CAUSE() if ($thread->{pt_execute}->PT_STATE() == PT_ERROR);
$thread->{response} = $thread->{pt_execute}->PT_RETVAL();
#-- reset the bus (needed to stop receiving data ?) #-- reset the bus (needed to stop receiving data ?)
OWX_ASYNC_Execute( $master, $thread, 1, undef, undef, undef ); $thread->{pt_execute} = OWX_ASYNC_PT_Execute($master,1,undef,undef,undef);
$thread->{TimeoutTime} = gettimeofday()+2; #TODO: implement attribute-based timeout
PT_WAIT_THREAD($thread->{pt_execute});
delete $thread->{TimeoutTime};
die $thread->{pt_execute}->PT_CAUSE() if ($thread->{pt_execute}->PT_STATE() == PT_ERROR);
unless ($response->{success}) { if (my $ret = OWXCOUNT_BinValues($hash,"getpage.".$page.($final ? ".final" : ""),$owx_dev,$thread->{'select'},$thread->{response})) {
PT_EXIT("device $owx_dev error reading page $page"); die $ret;
}
$res = $response->{readdata};
#TODO validate whether testing '0' is appropriate with async interface
if( $res eq 0 ) {
PT_EXIT("device $owx_dev error reading page $page");
}
$res = OWXCOUNT_BinValues($hash,"getpage.".$page.($final ? ".final" : ""),1,1,$owx_dev,$response->{writedata},$response->{numread},$res);
if ($res) {
PT_EXIT($res);
} }
PT_END; PT_END;
});
} }
######################################################################################## ########################################################################################
@ -1883,9 +1917,12 @@ sub OWXCOUNT_PT_GetPage($$$) {
sub OWXCOUNT_PT_SetPage($$$) { sub OWXCOUNT_PT_SetPage($$$) {
my ($thread,$hash,$page,$data) = @_; my ($hash,$page,$data) = @_;
my ($select, $res, $response); return PT_THREAD(sub {
my ($thread) = @_;
my ($res, $response);
#-- ID of the device, hash of the busmaster #-- ID of the device, hash of the busmaster
my $owx_dev = $hash->{ROM_ID}; my $owx_dev = $hash->{ROM_ID};
@ -1906,93 +1943,64 @@ sub OWXCOUNT_PT_SetPage($$$) {
my $ta2 = ($page*32) >> 8; my $ta2 = ($page*32) >> 8;
my $ta1 = ($page*32) & 255; my $ta1 = ($page*32) & 255;
#Log 1, "OWXCOUNT: setting page Nr. $ta2 $ta1 $data"; #Log 1, "OWXCOUNT: setting page Nr. $ta2 $ta1 $data";
$select=sprintf("\x0F%c%c",$ta1,$ta2).$data; $thread->{'select'}=sprintf("\x0F%c%c",$ta1,$ta2).$data;
#-- first command, next 2 are address, then data
#$res2 = "OWCOUNT SET PAGE 1 device $owx_dev ";
#for($i=0;$i<10;$i++){
# $j=int(ord(substr($select,$i,1))/16);
# $k=ord(substr($select,$i,1))%16;
# $res2.=sprintf "0x%1x%1x ",$j,$k;
#}
#main::Log(1, $res2);
#"setpage.1" #"setpage.1"
unless (OWX_ASYNC_Execute( $master, $thread, 1, $owx_dev, $select, 0)) { $thread->{pt_execute} = OWX_ASYNC_PT_Execute($master,1,$owx_dev, $thread->{'select'}, 0 );
PT_EXIT("device $owx_dev not accessible in writing scratchpad"); $thread->{TimeoutTime} = gettimeofday()+2; #TODO: implement attribute-based timeout
} PT_WAIT_THREAD($thread->{pt_execute});
PT_WAIT_UNTIL($thread->{ExecuteResponse}); delete $thread->{TimeoutTime};
unless ($thread->{ExecuteResponse}->{success}) { die $thread->{pt_execute}->PT_CAUSE() if ($thread->{pt_execute}->PT_STATE() == PT_ERROR);
PT_EXIT("device $owx_dev error writing scratchpad");
}
#-- issue the match ROM command \x55 and the read scratchpad command #-- issue the match ROM command \x55 and the read scratchpad command
# \xAA, receiving 2 address bytes, 1 status byte and scratchpad content # \xAA, receiving 2 address bytes, 1 status byte and scratchpad content
$select = "\xAA"; $thread->{'select'} = "\xAA";
#-- reading 9 + 3 + up to 32 bytes #-- reading 9 + 3 + up to 32 bytes
# TODO: sometimes much less than 28 # TODO: sometimes much less than 28
#"setpage.2" #"setpage.2"
unless (OWX_ASYNC_Execute( $master, $thread, 1, $owx_dev, $select, 28)) { $thread->{pt_execute} = OWX_ASYNC_PT_Execute($master,1,$owx_dev, $thread->{'select'}, 28 );
PT_EXIT("device $owx_dev not accessible in writing scratchpad"); $thread->{TimeoutTime} = gettimeofday()+2; #TODO: implement attribute-based timeout
} PT_WAIT_THREAD($thread->{pt_execute});
PT_WAIT_UNTIL($thread->{ExecuteResponse}); delete $thread->{TimeoutTime};
$response = $thread->{ExecuteResponse}; die $thread->{pt_execute}->PT_CAUSE() if ($thread->{pt_execute}->PT_STATE() == PT_ERROR);
unless ($response->{success}) { $res = $thread->{pt_execute}->PT_RETVAL();
PT_EXIT("device $owx_dev error writing scratchpad");
}
$res = $response->{readdata};
if( length($res) < 13 ){ if( length($res) < 13 ){
PT_EXIT("device $owx_dev not accessible in reading scratchpad"); PT_EXIT("device $owx_dev not accessible in reading scratchpad");
} }
#-- first 1 command, next 2 are address, then data
#$res3 = substr($res,9,10);
#$res2 = "OWCOUNT SET PAGE 2 device $owx_dev ";
#for($i=0;$i<10;$i++){
# $j=int(ord(substr($res3,$i,1))/16);
# $k=ord(substr($res3,$i,1))%16;
# $res2.=sprintf "0x%1x%1x ",$j,$k;
#}
#main::Log(1, $res2);
#-- issue the match ROM command \x55 and the copy scratchpad command #-- issue the match ROM command \x55 and the copy scratchpad command
# \x5A followed by 3 byte authentication code obtained in previous read # \x5A followed by 3 byte authentication code obtained in previous read
$select="\x5A".substr($res,0,3); $thread->{'select'}="\x5A".substr($res,0,3);
#-- first command, next 2 are address, then data #-- first command, next 2 are address, then data
#$res2 = "OWCOUNT SET PAGE 3 device $owx_dev ";
#for($i=0;$i<10;$i++){
# $j=int(ord(substr($select,$i,1))/16);
# $k=ord(substr($select,$i,1))%16;
# $res2.=sprintf "0x%1x%1x ",$j,$k;
#}
#main::Log(1, $res2);
#"setpage.3" #"setpage.3"
unless (OWX_ASYNC_Execute( $master, $thread, 1, $owx_dev, $select, 6)) { $thread->{pt_execute} = OWX_ASYNC_PT_Execute($master,1,$owx_dev, $thread->{'select'}, 6 );
PT_EXIT("device $owx_dev not accessible for copying scratchpad"); $thread->{TimeoutTime} = gettimeofday()+2; #TODO: implement attribute-based timeout
} PT_WAIT_THREAD($thread->{pt_execute});
PT_WAIT_UNTIL($thread->{ExecuteResponse}); delete $thread->{TimeoutTime};
$response = $thread->{ExecuteResponse}; die $thread->{pt_execute}->PT_CAUSE() if ($thread->{pt_execute}->PT_STATE() == PT_ERROR);
unless ($response->{success}) { $res = $thread->{pt_execute}->PT_RETVAL();
PT_EXIT("device $owx_dev error copying scratchpad");
}
$res = $response->{readdata};
#TODO validate whether testing '0' is appropriate with async interface #TODO validate whether testing '0' is appropriate with async interface
#-- process results #-- process results
if( $res eq 0 ){ if( $res eq 0 ){
PT_EXIT("device $owx_dev error copying scratchpad"); PT_EXIT("device $owx_dev error copying scratchpad");
} }
PT_END; PT_END;
});
} }
sub OWXCOUNT_PT_InitializeDevicePage($$$) { sub OWXCOUNT_PT_InitializeDevicePage($$$) {
my ($thread,$hash,$page,$newdata) = @_; my ($hash,$page,$newdata) = @_;
return PT_THREAD(sub {
my ($thread) = @_;
my $ret; my $ret;
PT_BEGIN($thread); PT_BEGIN($thread);
$thread->{task} = PT_THREAD(\&OWXCOUNT_PT_GetPage); $thread->{task} = OWXCOUNT_PT_GetPage($hash,$page,0);
PT_WAIT_THREAD($thread->{task},$hash,$page,0); PT_WAIT_THREAD($thread->{task});
$ret = $thread->{task}->PT_RETVAL(); $ret = $thread->{task}->PT_RETVAL();
if ($ret) { if ($ret) {
PT_EXIT($ret); PT_EXIT($ret);
@ -2000,27 +2008,28 @@ sub OWXCOUNT_PT_InitializeDevicePage($$$) {
$thread->{olddata} = $hash->{owg_str}->[14]; $thread->{olddata} = $hash->{owg_str}->[14];
$thread->{task} = PT_THREAD(\&OWXCOUNT_PT_SetPage); $thread->{task} = OWXCOUNT_PT_SetPage($hash,$page,$newdata);
PT_WAIT_THREAD($thread->{task},$hash,$page,$newdata); PT_WAIT_THREAD($thread->{task});
$ret = $thread->{task}->PT_RETVAL(); $ret = $thread->{task}->PT_RETVAL();
if ($ret) { if ($ret) {
PT_EXIT($ret); PT_EXIT($ret);
} }
$thread->{task} = PT_THREAD(\&OWXCOUNT_PT_GetPage); $thread->{task} = OWXCOUNT_PT_GetPage($hash,$page,0);
PT_WAIT_THREAD($thread->{task},$hash,$page,0); PT_WAIT_THREAD($thread->{task});
$ret = $thread->{task}->PT_RETVAL(); $ret = $thread->{task}->PT_RETVAL();
if ($ret) { if ($ret) {
PT_EXIT($ret); PT_EXIT($ret);
} }
$thread->{task} = PT_THREAD(\&OWXCOUNT_PT_SetPage); $thread->{task} = OWXCOUNT_PT_SetPage($hash,$page,$thread->{olddata});
PT_WAIT_THREAD($thread->{task},$hash,$page,$thread->{olddata}); PT_WAIT_THREAD($thread->{task});
$ret = $thread->{task}->PT_RETVAL(); $ret = $thread->{task}->PT_RETVAL();
if ($ret) { if ($ret) {
PT_EXIT($ret); PT_EXIT($ret);
} }
PT_END; PT_END;
});
} }
1; 1;

View File

@ -49,13 +49,26 @@
package main; package main;
use vars qw{%attr %defs %modules $readingFnAttributes $init_done}; use vars qw{%attr %defs %modules $readingFnAttributes $init_done};
use Time::HiRes qw(usleep ualarm gettimeofday tv_interval); use Time::HiRes qw(gettimeofday);
use strict; use strict;
use warnings; use warnings;
#add FHEM/lib to @INC if it's not allready included. Should rather be in fhem.pl than here though...
BEGIN {
if (!grep(/FHEM\/lib$/,@INC)) {
foreach my $inc (grep(/FHEM$/,@INC)) {
push @INC,$inc."/lib";
};
};
};
use GPUtils qw(:all);
use ProtoThreads;
no warnings 'deprecated';
sub Log($$); sub Log($$);
my $owx_version="5.12"; my $owx_version="5.13";
#-- declare variables #-- declare variables
my %gets = ( my %gets = (
"present" => "", "present" => "",
@ -92,6 +105,8 @@ sub OWID_Initialize ($) {
$hash->{GetFn} = "OWID_Get"; $hash->{GetFn} = "OWID_Get";
$hash->{SetFn} = "OWID_Set"; $hash->{SetFn} = "OWID_Set";
$hash->{AttrFn} = "OWID_Attr"; $hash->{AttrFn} = "OWID_Attr";
$hash->{NotifyFn} = "OWID_Notify";
$hash->{InitFn} = "OWID_Init";
$hash->{AttrList} = "IODev do_not_notify:0,1 showtime:0,1 model loglevel:0,1,2,3,4,5 ". $hash->{AttrList} = "IODev do_not_notify:0,1 showtime:0,1 model loglevel:0,1,2,3,4,5 ".
"interval ". "interval ".
$readingFnAttributes; $readingFnAttributes;
@ -199,12 +214,27 @@ sub OWID_Define ($$) {
readingsSingleUpdate($hash,"state","Defined",1); readingsSingleUpdate($hash,"state","Defined",1);
Log 3, "OWID: Device $name defined."; Log 3, "OWID: Device $name defined.";
#-- Initialization reading according to interface type $hash->{NOTIFYDEV} = "global";
my $interface= $hash->{IODev}->{TYPE};
if ($init_done) {
return OWID_Init($hash);
}
return undef;
}
sub OWID_Notify ($$) {
my ($hash,$dev) = @_;
if( grep(m/^(INITIALIZED|REREADCFG)$/, @{$dev->{CHANGED}}) ) {
OWID_Init($hash);
} elsif( grep(m/^SAVE$/, @{$dev->{CHANGED}}) ) {
}
}
sub OWID_Init ($) {
my ($hash)=@_;
#-- Start timer for updates #-- Start timer for updates
InternalTimer(time()+5+$hash->{INTERVAL}, "OWID_GetValues", $hash, 0); RemoveInternalTimer($hash);
InternalTimer(gettimeofday()+10, "OWID_GetValues", $hash, 0);
#-- #--
readingsSingleUpdate($hash,"state","Initialized",1); readingsSingleUpdate($hash,"state","Initialized",1);
@ -248,6 +278,9 @@ sub OWID_Attr(@) {
AssignIoPort($hash,$value); AssignIoPort($hash,$value);
if( defined($hash->{IODev}) ) { if( defined($hash->{IODev}) ) {
$hash->{ASYNC} = $hash->{IODev}->{TYPE} eq "OWX_ASYNC" ? 1 : 0; $hash->{ASYNC} = $hash->{IODev}->{TYPE} eq "OWX_ASYNC" ? 1 : 0;
if ($init_done) {
OWID_Init($hash);
}
} }
last; last;
}; };
@ -301,7 +334,15 @@ sub OWID_Get($@) {
my $master = $hash->{IODev}; my $master = $hash->{IODev};
#-- asynchronous mode #-- asynchronous mode
if( $hash->{ASYNC} ){ if( $hash->{ASYNC} ){
$value = OWX_ASYNC_Verify($master,$hash->{ROM_ID}); my ($task,$task_state);
eval {
$task = OWX_ASYNC_PT_Verify($hash);
OWX_ASYNC_Schedule($hash,$task);
$task_state = OWX_ASYNC_RunToCompletion($master,$task);
};
return GP_Catch($@) if $@;
return $task->PT_CAUSE() if ($task_state == PT_ERROR or $task_state == PT_CANCELED);
return "$name.present => ".ReadingsVal($name,"present","unknown");
} else { } else {
$value = OWX_Verify($master,$hash->{ROM_ID}); $value = OWX_Verify($master,$hash->{ROM_ID});
} }
@ -344,22 +385,18 @@ sub OWID_GetValues($) {
#-- hash of the busmaster #-- hash of the busmaster
my $master = $hash->{IODev}; my $master = $hash->{IODev};
#-- measure elapsed time
my $t0 = [gettimeofday];
if( $hash->{ASYNC} ){ if( $hash->{ASYNC} ){
$value = OWX_ASYNC_Verify($master,$hash->{ROM_ID}); #TODO use OWX_ASYNC_Schedule instead
my $task = OWX_ASYNC_PT_Verify($hash);
eval {
OWX_ASYNC_Schedule($hash,$task);
};
return GP_Catch($@) if $@;
return undef;
} else { } else {
$value = OWX_Verify($master,$hash->{ROM_ID}); $value = OWX_Verify($master,$hash->{ROM_ID});
} }
#my $thr = threads->create('OWX_Verify', $master, $hash->{ROM_ID});
#$thr->detach();
my $t1 = [gettimeofday];
my $t0_t1 = tv_interval $t0, $t1;
#Log 1,"====> Time for verify = $t0_t1";
#-- generate an event only if presence has changed #-- generate an event only if presence has changed
if( $value == 0 ){ if( $value == 0 ){
readingsSingleUpdate($hash,"present",0,$hash->{PRESENT}); readingsSingleUpdate($hash,"present",0,$hash->{PRESENT});

View File

@ -58,6 +58,7 @@
package main; package main;
use vars qw{%attr %defs %modules $readingFnAttributes $init_done}; use vars qw{%attr %defs %modules $readingFnAttributes $init_done};
use Time::HiRes qw(gettimeofday);
use strict; use strict;
use warnings; use warnings;
@ -76,7 +77,7 @@ no warnings 'deprecated';
sub Log3($$$); sub Log3($$$);
my $owx_version="3.37"; my $owx_version="3.38";
#-- controller may be HD44780 or KS0073 #-- controller may be HD44780 or KS0073
# these values have to be changed for different display # these values have to be changed for different display
# geometries or memory maps # geometries or memory maps
@ -132,6 +133,7 @@ sub OWLCD_Initialize ($) {
$hash->{UndefFn} = "OWLCD_Undef"; $hash->{UndefFn} = "OWLCD_Undef";
$hash->{GetFn} = "OWLCD_Get"; $hash->{GetFn} = "OWLCD_Get";
$hash->{SetFn} = "OWLCD_Set"; $hash->{SetFn} = "OWLCD_Set";
$hash->{NotifyFn} = "OWLCD_Notify";
$hash->{InitFn} = "OWLCD_Init"; $hash->{InitFn} = "OWLCD_Init";
$hash->{AttrFn} = "OWLCD_Attr"; $hash->{AttrFn} = "OWLCD_Attr";
my $attlist = "IODev do_not_notify:0,1 showtime:0,1 ". my $attlist = "IODev do_not_notify:0,1 showtime:0,1 ".
@ -198,12 +200,22 @@ sub OWLCD_Define ($$) {
$hash->{STATE} = "Defined"; $hash->{STATE} = "Defined";
Log3 $name,3, "OWLCD: Device $name defined."; Log3 $name,3, "OWLCD: Device $name defined.";
if (($hash->{IODev}->{TYPE} eq "OWX") or $main::init_done) { $hash->{NOTIFYDEV} = "global";
if ($main::init_done) {
return OWLCD_Init($hash); return OWLCD_Init($hash);
} }
return undef; return undef;
} }
sub OWLCD_Notify ($$) {
my ($hash,$dev) = @_;
if( grep(m/^(INITIALIZED|REREADCFG)$/, @{$dev->{CHANGED}}) ) {
OWLCD_Init($hash);
} elsif( grep(m/^SAVE$/, @{$dev->{CHANGED}}) ) {
}
}
sub OWLCD_Init($) { sub OWLCD_Init($) {
my ($hash) = @_; my ($hash) = @_;
#-- Initialization reading according to interface type #-- Initialization reading according to interface type
@ -221,11 +233,11 @@ sub OWLCD_Init($) {
eval { eval {
OWXLCD_InitializeDevice($hash); OWXLCD_InitializeDevice($hash);
#-- set backlight on #-- set backlight on
OWX_ASYNC_Schedule($hash,PT_THREAD(\&OWXLCD_PT_SetFunction),$hash,"bklon",0); OWX_ASYNC_Schedule($hash,OWXLCD_PT_SetFunction($hash,"bklon",0));
#-- erase all icons #-- erase all icons
OWX_ASYNC_Schedule($hash,PT_THREAD(\&OWXLCD_PT_SetIcon),$hash,0,0); OWX_ASYNC_Schedule($hash,OWXLCD_PT_SetIcon($hash,0,0));
#-- erase alarm state #-- erase alarm state
OWX_ASYNC_Schedule($hash,PT_THREAD(\&OWXLCD_PT_SetFunction),$hash,"gpio",15); OWX_ASYNC_Schedule($hash,OWXLCD_PT_SetFunction($hash,"gpio",15));
}; };
return GP_Catch($@) if $@; return GP_Catch($@) if $@;
#-- Unknown interface #-- Unknown interface
@ -257,6 +269,9 @@ sub OWLCD_Attr(@) {
AssignIoPort($hash,$value); AssignIoPort($hash,$value);
if( defined($hash->{IODev}) ) { if( defined($hash->{IODev}) ) {
$hash->{ASYNC} = $hash->{IODev}->{TYPE} eq "OWX_ASYNC" ? 1 : 0; $hash->{ASYNC} = $hash->{IODev}->{TYPE} eq "OWX_ASYNC" ? 1 : 0;
if ($main::init_done) {
return OWLCD_Init($hash);
}
} }
last; last;
}; };
@ -302,13 +317,22 @@ sub OWLCD_Get($@) {
return "$name.id => $value"; return "$name.id => $value";
} }
#-- get present
if($a[1] eq "present") {
#-- hash of the busmaster #-- hash of the busmaster
my $master = $hash->{IODev}; my $master = $hash->{IODev};
#-- get present
if($a[1] eq "present") {
#-- asynchronous mode #-- asynchronous mode
if( $hash->{ASYNC} ){ if( $hash->{ASYNC} ){
$value = OWX_ASYNC_Verify($master,$hash->{ROM_ID}); my ($task,$task_state);
eval {
$task = OWX_ASYNC_PT_Verify($hash);
OWX_ASYNC_Schedule($hash,$task);
$task_state = OWX_ASYNC_RunToCompletion($master,$task);
};
return GP_Catch($@) if $@;
return $task->PT_CAUSE() if ($task_state == PT_ERROR or $task_state == PT_CANCELED);
return "$name.present => ".ReadingsVal($name,"present","unknown");
} else { } else {
$value = OWX_Verify($master,$hash->{ROM_ID}); $value = OWX_Verify($master,$hash->{ROM_ID});
} }
@ -319,11 +343,13 @@ sub OWLCD_Get($@) {
#-- get gpio states #-- get gpio states
if($a[1] eq "gpio") { if($a[1] eq "gpio") {
if ($hash->{ASYNC}) { if ($hash->{ASYNC}) {
my $task = PT_THREAD(\&OWXLCD_PT_Get); my ($task,$task_state);
eval { eval {
while ($task->PT_SCHEDULE($hash,"gpio")) { OWX_ASYNC_Poll($hash->{IODev}); }; $task = OWXLCD_PT_Get($hash,"gpio");
OWX_ASYNC_Schedule($hash,$task);
$task_state = OWX_ASYNC_RunToCompletion($master,$task);
}; };
$ret = ($@) ? GP_Catch($@) : $task->PT_RETVAL(); $ret = ($@) ? GP_Catch($@) : ($task_state == PT_ERROR or $task_state == PT_CANCELED) ? $task->PT_CAUSE() : $task->PT_RETVAL();
return $ret if $ret; return $ret if $ret;
return "$name.gpio => ".main::ReadingsVal($hash->{NAME},"gpio",""); return "$name.gpio => ".main::ReadingsVal($hash->{NAME},"gpio","");
} else { } else {
@ -335,11 +361,13 @@ sub OWLCD_Get($@) {
#-- get gpio counters #-- get gpio counters
if($a[1] eq "counter") { if($a[1] eq "counter") {
if ($hash->{ASYNC}) { if ($hash->{ASYNC}) {
my $task = PT_THREAD(\&OWXLCD_PT_Get); my ($task,$task_state);
eval { eval {
while ($task->PT_SCHEDULE($hash,"counter")) { OWX_ASYNC_Poll($hash->{IODev}); }; $task = OWXLCD_PT_Get($hash,"counter");
OWX_ASYNC_Schedule($hash,$task);
$task_state = OWX_ASYNC_RunToCompletion($master,$task);
}; };
$ret = ($@) ? GP_Catch($@) : $task->PT_RETVAL(); $ret = ($@) ? GP_Catch($@) : ($task_state == PT_ERROR or $task_state == PT_CANCELED) ? $task->PT_CAUSE() : $task->PT_RETVAL();
return $ret if $ret; return $ret if $ret;
return "$name.counter => ".main::ReadingsVal($hash->{NAME},"counter",""); return "$name.counter => ".main::ReadingsVal($hash->{NAME},"counter","");
} else { } else {
@ -351,11 +379,13 @@ sub OWLCD_Get($@) {
#-- get version #-- get version
if($a[1] eq "version") { if($a[1] eq "version") {
if ($hash->{ASYNC}) { if ($hash->{ASYNC}) {
my $task = PT_THREAD(\&OWXLCD_PT_Get); my ($task,$task_state);
eval { eval {
while ($task->PT_SCHEDULE($hash,"version")) { OWX_ASYNC_Poll($hash->{IODev}); }; $task = OWXLCD_PT_Get($hash,"version");
OWX_ASYNC_Schedule($hash,$task);
$task_state = OWX_ASYNC_RunToCompletion($master,$task);
}; };
$ret = ($@) ? GP_Catch($@) : $task->PT_RETVAL(); $ret = ($@) ? GP_Catch($@) : ($task_state == PT_ERROR or $task_state == PT_CANCELED) ? $task->PT_CAUSE() : $task->PT_RETVAL();
return $ret if $ret; return $ret if $ret;
return "$name.gpio => ".main::ReadingsVal($hash->{NAME},"version",""); return "$name.gpio => ".main::ReadingsVal($hash->{NAME},"version","");
} else { } else {
@ -369,11 +399,13 @@ sub OWLCD_Get($@) {
my $page = (defined $a[2] and $a[2] =~ m/\d/) ? int($a[2]) : 0; my $page = (defined $a[2] and $a[2] =~ m/\d/) ? int($a[2]) : 0;
Log3 $name,1,"Calling GetMemory with page $page"; Log3 $name,1,"Calling GetMemory with page $page";
if ($hash->{ASYNC}) { if ($hash->{ASYNC}) {
my $task = PT_THREAD(\&OWXLCD_PT_GetMemory); my ($task,$task_state);
eval { eval {
while ($task->PT_SCHEDULE($hash,$page)) { OWX_ASYNC_Poll($hash->{IODev}); }; $task = OWXLCD_PT_GetMemory($hash,$page);
OWX_ASYNC_Schedule($hash,$task);
$task_state = OWX_ASYNC_RunToCompletion($master,$task);
}; };
$ret = ($@) ? GP_Catch($@) : $task->PT_RETVAL(); $ret = ($@) ? GP_Catch($@) : ($task_state == PT_ERROR or $task_state == PT_CANCELED) ? $task->PT_CAUSE() : $task->PT_RETVAL();
return $ret if $ret; return $ret if $ret;
return "$name $reading $page => ".main::ReadingsVal($hash->{NAME},"memory$page",""); return "$name $reading $page => ".main::ReadingsVal($hash->{NAME},"memory$page","");
} else { } else {
@ -468,7 +500,7 @@ sub OWLCD_Set($@) {
if( ! ((int($value) >= 0) && (int($value) <= 7)) ); if( ! ((int($value) >= 0) && (int($value) <= 7)) );
if ($hash->{ASYNC}) { if ($hash->{ASYNC}) {
eval { eval {
OWX_ASYNC_Schedule( $hash, PT_THREAD(\&OWXLCD_PT_SetFunction), $hash, "gpio", int($value) ); OWX_ASYNC_Schedule( $hash, OWXLCD_PT_SetFunction($hash, "gpio", int($value)) );
}; };
return GP_Catch($@) if $@; return GP_Catch($@) if $@;
} else { } else {
@ -483,7 +515,7 @@ sub OWLCD_Set($@) {
if( uc($value) eq "ON"){ if( uc($value) eq "ON"){
if ($hash->{ASYNC}) { if ($hash->{ASYNC}) {
eval { eval {
OWX_ASYNC_Schedule( $hash, PT_THREAD(\&OWXLCD_PT_SetFunction), $hash, "lcdon", 0 ); OWX_ASYNC_Schedule( $hash, OWXLCD_PT_SetFunction($hash, "lcdon", 0) );
}; };
return GP_Catch($@) if $@; return GP_Catch($@) if $@;
} else { } else {
@ -492,7 +524,7 @@ sub OWLCD_Set($@) {
}elsif( uc($value) eq "OFF" ){ }elsif( uc($value) eq "OFF" ){
if ($hash->{ASYNC}) { if ($hash->{ASYNC}) {
eval { eval {
OWX_ASYNC_Schedule( $hash, PT_THREAD(\&OWXLCD_PT_SetFunction), $hash, "lcdoff", 0 ); OWX_ASYNC_Schedule( $hash, OWXLCD_PT_SetFunction($hash, "lcdoff", 0) );
}; };
return GP_Catch($@) if $@; return GP_Catch($@) if $@;
} else { } else {
@ -510,7 +542,7 @@ sub OWLCD_Set($@) {
if( uc($value) eq "ON"){ if( uc($value) eq "ON"){
if ($hash->{ASYNC}) { if ($hash->{ASYNC}) {
eval { eval {
OWX_ASYNC_Schedule( $hash, PT_THREAD(\&OWXLCD_PT_SetFunction), $hash, "blkon", 0 ); OWX_ASYNC_Schedule( $hash, OWXLCD_PT_SetFunction($hash, "blkon", 0) );
}; };
return GP_Catch($@) if $@; return GP_Catch($@) if $@;
} else { } else {
@ -519,7 +551,7 @@ sub OWLCD_Set($@) {
}elsif( uc($value) eq "OFF" ){ }elsif( uc($value) eq "OFF" ){
if ($hash->{ASYNC}) { if ($hash->{ASYNC}) {
eval { eval {
OWX_ASYNC_Schedule( $hash, PT_THREAD(\&OWXLCD_PT_SetFunction), $hash, "blkoff", 0 ); OWX_ASYNC_Schedule( $hash, OWXLCD_PT_SetFunction($hash, "blkoff", 0) );
}; };
return GP_Catch($@) if $@; return GP_Catch($@) if $@;
} else { } else {
@ -535,9 +567,9 @@ sub OWLCD_Set($@) {
if($key eq "reset") { if($key eq "reset") {
if ($hash->{ASYNC}) { if ($hash->{ASYNC}) {
eval { eval {
OWX_ASYNC_Schedule( $hash, PT_THREAD(\&OWXLCD_PT_SetFunction), $hash, "reset", 0 ); OWX_ASYNC_Schedule( $hash, OWXLCD_PT_SetFunction($hash, "reset", 0) );
OWX_ASYNC_Schedule( $hash, PT_THREAD(\&OWXLCD_PT_SetIcon), $hash, 0, 0 ); OWX_ASYNC_Schedule( $hash, OWXLCD_PT_SetIcon($hash, 0, 0) );
OWX_ASYNC_Schedule( $hash, PT_THREAD(\&OWXLCD_PT_SetFunction), $hash, "gpio", 15 ); OWX_ASYNC_Schedule( $hash, OWXLCD_PT_SetFunction($hash, "gpio", 15) );
}; };
return GP_Catch($@) if $@; return GP_Catch($@) if $@;
} else { } else {
@ -557,7 +589,7 @@ sub OWLCD_Set($@) {
if( uc($value) eq "OFF" ){ if( uc($value) eq "OFF" ){
if ($hash->{ASYNC}) { if ($hash->{ASYNC}) {
eval { eval {
OWX_ASYNC_Schedule( $hash, PT_THREAD(\&OWXLCD_PT_SetIcon), $hash, 16, 0 ); OWX_ASYNC_Schedule( $hash, OWXLCD_PT_SetIcon($hash, 16, 0) );
}; };
return GP_Catch($@) if $@; return GP_Catch($@) if $@;
} else { } else {
@ -566,7 +598,7 @@ sub OWLCD_Set($@) {
}elsif( uc($value) eq "BLINK" ){ }elsif( uc($value) eq "BLINK" ){
if ($hash->{ASYNC}) { if ($hash->{ASYNC}) {
eval { eval {
OWX_ASYNC_Schedule( $hash, PT_THREAD(\&OWXLCD_PT_SetIcon), $hash, 16, 6 ); OWX_ASYNC_Schedule( $hash, OWXLCD_PT_SetIcon($hash, 16, 6) );
}; };
return GP_Catch($@) if $@; return GP_Catch($@) if $@;
} else { } else {
@ -575,7 +607,7 @@ sub OWLCD_Set($@) {
}elsif( ((int($value) > 0) && (int($value) < 6)) ){ }elsif( ((int($value) > 0) && (int($value) < 6)) ){
if ($hash->{ASYNC}) { if ($hash->{ASYNC}) {
eval { eval {
OWX_ASYNC_Schedule( $hash, PT_THREAD(\&OWXLCD_PT_SetIcon), $hash, 16, int($value) ); OWX_ASYNC_Schedule( $hash, OWXLCD_PT_SetIcon($hash, 16, int($value)) );
}; };
return GP_Catch($@) if $@; return GP_Catch($@) if $@;
} else { } else {
@ -588,7 +620,7 @@ sub OWLCD_Set($@) {
if( uc($value) eq "OFF"){ if( uc($value) eq "OFF"){
if ($hash->{ASYNC}) { if ($hash->{ASYNC}) {
eval { eval {
OWX_ASYNC_Schedule( $hash, PT_THREAD(\&OWXLCD_PT_SetIcon), $hash, $icon, 0 ); OWX_ASYNC_Schedule( $hash, OWXLCD_PT_SetIcon($hash, $icon, 0) );
}; };
return GP_Catch($@) if $@; return GP_Catch($@) if $@;
} else { } else {
@ -597,7 +629,7 @@ sub OWLCD_Set($@) {
}elsif( uc($value) eq "ON" ){ }elsif( uc($value) eq "ON" ){
if ($hash->{ASYNC}) { if ($hash->{ASYNC}) {
eval { eval {
OWX_ASYNC_Schedule( $hash, PT_THREAD(\&OWXLCD_PT_SetIcon), $hash, $icon, 1 ); OWX_ASYNC_Schedule( $hash, OWXLCD_PT_SetIcon($hash, $icon, 1) );
}; };
return GP_Catch($@) if $@; return GP_Catch($@) if $@;
} else { } else {
@ -606,7 +638,7 @@ sub OWLCD_Set($@) {
}elsif( uc($value) eq "BLINK" ){ }elsif( uc($value) eq "BLINK" ){
if ($hash->{ASYNC}) { if ($hash->{ASYNC}) {
eval { eval {
OWX_ASYNC_Schedule( $hash, PT_THREAD(\&OWXLCD_PT_SetIcon), $hash, $icon, 2 ); OWX_ASYNC_Schedule( $hash, &OWXLCD_PT_SetIcon($hash, $icon, 2) );
}; };
return GP_Catch($@) if $@; return GP_Catch($@) if $@;
} else { } else {
@ -629,7 +661,7 @@ sub OWLCD_Set($@) {
#-- check value and write to device #-- check value and write to device
if ($hash->{ASYNC}) { if ($hash->{ASYNC}) {
eval { eval {
OWX_ASYNC_Schedule( $hash, PT_THREAD(\&OWXLCD_PT_SetLine), $hash, $line, $value ); OWX_ASYNC_Schedule( $hash, OWXLCD_PT_SetLine($hash, $line, $value) );
}; };
return GP_Catch($@) if $@; return GP_Catch($@) if $@;
} else { } else {
@ -648,7 +680,7 @@ sub OWLCD_Set($@) {
Log3 $name,1,"Calling SetMemory with page $line"; Log3 $name,1,"Calling SetMemory with page $line";
if ($hash->{ASYNC}) { if ($hash->{ASYNC}) {
eval { eval {
OWX_ASYNC_Schedule( $hash, PT_THREAD(\&OWXLCD_PT_SetMemory), $hash, $line, $value ); OWX_ASYNC_Schedule( $hash, OWXLCD_PT_SetMemory($hash, $line, $value) );
}; };
return GP_Catch($@) if $@; return GP_Catch($@) if $@;
} else { } else {
@ -662,7 +694,7 @@ sub OWLCD_Set($@) {
if(lc($value) eq "beep") { if(lc($value) eq "beep") {
if ($hash->{ASYNC}) { if ($hash->{ASYNC}) {
eval { eval {
OWX_ASYNC_Schedule( $hash, PT_THREAD(\&OWXLCD_PT_SetFunction), $hash, "gpio", 14 ); OWX_ASYNC_Schedule( $hash, OWXLCD_PT_SetFunction($hash, "gpio", 14) );
}; };
return GP_Catch($@) if $@; return GP_Catch($@) if $@;
} else { } else {
@ -672,7 +704,7 @@ sub OWLCD_Set($@) {
}elsif(lc($value) eq "red") { }elsif(lc($value) eq "red") {
if ($hash->{ASYNC}) { if ($hash->{ASYNC}) {
eval { eval {
OWX_ASYNC_Schedule( $hash, PT_THREAD(\&OWXLCD_PT_SetFunction), $hash, "gpio", 13 ); OWX_ASYNC_Schedule( $hash, OWXLCD_PT_SetFunction($hash, "gpio", 13) );
}; };
return GP_Catch($@) if $@; return GP_Catch($@) if $@;
} else { } else {
@ -682,7 +714,7 @@ sub OWLCD_Set($@) {
}elsif(lc($value) eq "yellow") { }elsif(lc($value) eq "yellow") {
if ($hash->{ASYNC}) { if ($hash->{ASYNC}) {
eval { eval {
OWX_ASYNC_Schedule( $hash, PT_THREAD(\&OWXLCD_PT_SetFunction), $hash, "gpio", 11 ); OWX_ASYNC_Schedule( $hash, OWXLCD_PT_SetFunction($hash, "gpio", 11) );
}; };
return GP_Catch($@) if $@; return GP_Catch($@) if $@;
} else { } else {
@ -692,7 +724,7 @@ sub OWLCD_Set($@) {
}elsif( (lc($value) eq "off") || (lc($value) eq "none") ) { }elsif( (lc($value) eq "off") || (lc($value) eq "none") ) {
if ($hash->{ASYNC}) { if ($hash->{ASYNC}) {
eval { eval {
OWX_ASYNC_Schedule( $hash, PT_THREAD(\&OWXLCD_PT_SetFunction), $hash, "gpio", 15 ); OWX_ASYNC_Schedule( $hash, OWXLCD_PT_SetFunction($hash, "gpio", 15) );
}; };
return GP_Catch($@) if $@; return GP_Catch($@) if $@;
} else { } else {
@ -708,10 +740,10 @@ sub OWLCD_Set($@) {
if($key eq "test") { if($key eq "test") {
if ($hash->{ASYNC}) { if ($hash->{ASYNC}) {
eval { eval {
OWX_ASYNC_Schedule( $hash, PT_THREAD(\&OWXLCD_PT_SetLine), $hash,0,"Hallo Welt"); OWX_ASYNC_Schedule( $hash, OWXLCD_PT_SetLine($hash,0,"Hallo Welt"));
OWX_ASYNC_Schedule( $hash, PT_THREAD(\&OWXLCD_PT_SetLine), $hash,1,"Mary had a big lamb"); OWX_ASYNC_Schedule( $hash, OWXLCD_PT_SetLine($hash,1,"Mary had a big lamb"));
OWX_ASYNC_Schedule( $hash, PT_THREAD(\&OWXLCD_PT_SetLine), $hash,2,"Solar 4.322 kW "); OWX_ASYNC_Schedule( $hash, OWXLCD_PT_SetLine($hash,2,"Solar 4.322 kW "));
OWX_ASYNC_Schedule( $hash, PT_THREAD(\&OWXLCD_PT_SetLine), $hash,3,"\x5B\x5C\x5E\x7B\x7C\x7E\xBE"); OWX_ASYNC_Schedule( $hash, OWXLCD_PT_SetLine($hash,3,"\x5B\x5C\x5E\x7B\x7C\x7E\xBE"));
}; };
return GP_Catch($@) if $@; return GP_Catch($@) if $@;
} else { } else {
@ -801,16 +833,15 @@ sub OWXLCD_Byte($$$) {
sub OWXLCD_PT_Byte($$$) { sub OWXLCD_PT_Byte($$$) {
my ($thread,$hash,$cmd,$byte) = @_; my ($hash,$cmd,$byte) = @_;
return PT_THREAD(sub {
my ($thread) = @_;
my ($select); my ($select);
#-- ID of the device #-- ID of the device
my $owx_dev = $hash->{ROM_ID}; my $owx_dev = $hash->{ROM_ID};
#-- hash of the busmaster #-- hash of the busmaster
my $master = $hash->{IODev}; my $master = $hash->{IODev};
my ($i,$j,$k); my ($i,$j,$k);
PT_BEGIN($thread); PT_BEGIN($thread);
@ -825,18 +856,17 @@ sub OWXLCD_PT_Byte($$$) {
$select = sprintf("\x12%c",$byte); $select = sprintf("\x12%c",$byte);
#=============== wrong value requested =============================== #=============== wrong value requested ===============================
} else { } else {
return "OWXLCD: Wrong byte write attempt"; die "OWXLCD: Wrong byte write attempt";
} }
#"byte" #"byte"
unless (OWX_ASYNC_Execute( $master, $thread, 1, $owx_dev, $select, 0 )) { $thread->{pt_execute} = OWX_ASYNC_PT_Execute($master,1,$owx_dev,$select,0);
PT_EXIT("OWLCD: Device $owx_dev not accessible for writing a byte"); $thread->{TimeoutTime} = gettimeofday()+2; #TODO: implement attribute-based timeout
} PT_WAIT_THREAD($thread->{pt_execute});
PT_WAIT_UNTIL($thread->{ExecuteResponse}); delete $thread->{TimeoutTime};
unless ($thread->{ExecuteResponse}->{success}) { die $thread->{pt_execute}->PT_CAUSE() if ($thread->{pt_execute}->PT_STATE() == PT_ERROR);
PT_EXIT("OWLCD: Device $owx_dev error writing a byte");
}
PT_END; PT_END;
});
} }
######################################################################################## ########################################################################################
@ -913,8 +943,11 @@ sub OWXLCD_Get($$) {
sub OWXLCD_PT_Get($$) { sub OWXLCD_PT_Get($$) {
my ($thread,$hash,$cmd) = @_; my ($hash,$cmd) = @_;
return PT_THREAD(sub {
my ($thread) = @_;
my ($select); my ($select);
#-- ID of the device #-- ID of the device
@ -942,29 +975,26 @@ sub OWXLCD_PT_Get($$) {
$select = "\x41"; $select = "\x41";
$thread->{len} = 16; $thread->{len} = 16;
} else { } else {
PT_EXIT("OWXLCD: Wrong get attempt"); die("OWXLCD: Wrong get attempt");
} }
#"get.prepare" #"get.prepare"
unless (OWX_ASYNC_Execute( $master, $thread, 1, $owx_dev, $select, 0 )) { $thread->{pt_execute} = OWX_ASYNC_PT_Execute($master,1,$owx_dev,$select,0);
PT_EXIT("OWLCD: Device $owx_dev not accessible for reading"); $thread->{TimeoutTime} = gettimeofday()+2; #TODO: implement attribute-based timeout
} PT_WAIT_THREAD($thread->{pt_execute});
PT_WAIT_UNTIL($thread->{ExecuteResponse}); delete $thread->{TimeoutTime};
unless ($thread->{ExecuteResponse}->{success}) { die $thread->{pt_execute}->PT_CAUSE() if ($thread->{pt_execute}->PT_STATE() == PT_ERROR);
PT_EXIT("OWLCD: Device $owx_dev error writing a byte");
}
#-- issue the read scratchpad command \xBE #-- issue the read scratchpad command \xBE
unless (OWX_ASYNC_Execute( $master, $thread, 1, $owx_dev, "\xBE", $thread->{len} )) { $thread->{pt_execute} = OWX_ASYNC_PT_Execute($master,1,$owx_dev,"\xBE", $thread->{len});
PT_EXIT("OWLCD: Device $owx_dev not accessible for reading in 2nd step"); $thread->{TimeoutTime} = gettimeofday()+2; #TODO: implement attribute-based timeout
} PT_WAIT_THREAD($thread->{pt_execute});
PT_WAIT_UNTIL($thread->{ExecuteResponse}); delete $thread->{TimeoutTime};
my $response = $thread->{ExecuteResponse}; die $thread->{pt_execute}->PT_CAUSE() if ($thread->{pt_execute}->PT_STATE() == PT_ERROR);
unless ($response->{success}) {
PT_EXIT("OWLCD: Device $owx_dev error writing a byte"); OWXLCD_BinValues($hash, "get.".$cmd, 1, 1, $owx_dev, "\xBE", $thread->{len}, $thread->{pt_execute}->PT_RETVAL());
}
OWXLCD_BinValues($hash, "get.".$cmd, 1, 1, $owx_dev, $response->{writedata}, $response->{numread}, $response->{readdata});
PT_END; PT_END;
});
} }
######################################################################################## ########################################################################################
@ -1033,8 +1063,11 @@ sub OWXLCD_GetMemory($$) {
sub OWXLCD_PT_GetMemory($$) { sub OWXLCD_PT_GetMemory($$) {
my ($thread,$hash,$page) = @_; my ($hash,$page) = @_;
return PT_THREAD(sub {
my ($thread) = @_;
my ($select); my ($select);
#-- ID of the device #-- ID of the device
@ -1048,34 +1081,32 @@ sub OWXLCD_PT_GetMemory($$) {
#Log 1," page read is ".$page; #Log 1," page read is ".$page;
$select = sprintf("\4E%c\x10\x37",$page); $select = sprintf("\4E%c\x10\x37",$page);
#"prepare" #"prepare"
unless (OWX_ASYNC_Execute( $master, $thread, 1, $owx_dev, $select, 0 )) { $thread->{pt_execute} = OWX_ASYNC_PT_Execute($master,1,$owx_dev,$select,0);
PT_EXIT("OWLCD: Device $owx_dev not accessible for reading memory"); $thread->{TimeoutTime} = gettimeofday()+2; #TODO: implement attribute-based timeout
} PT_WAIT_THREAD($thread->{pt_execute});
PT_WAIT_UNTIL($thread->{ExecuteResponse}); delete $thread->{TimeoutTime};
unless ($thread->{ExecuteResponse}->{success}) { die $thread->{pt_execute}->PT_CAUSE() if ($thread->{pt_execute}->PT_STATE() == PT_ERROR);
PT_EXIT("OWLCD: Device $owx_dev error reading memory");
}
#-- sleeping for some time #-- sleeping for some time
#select(undef,undef,undef,0.5); $thread->{ExecuteTime} = gettimeofday()+0.5;
PT_YIELD_UNTIL(gettimeofday() >= $thread->{ExecuteTime});
delete $thread->{ExecuteTime};
#-- issue the match ROM command \x55 and the read scratchpad command \xBE #-- issue the match ROM command \x55 and the read scratchpad command \xBE
$select = "\xBE"; $thread->{'select'} = "\xBE";
#"get.memory.$page" #"get.memory.$page"
unless (OWX_ASYNC_Execute( $master, $thread, 1, $owx_dev, $select,16 )) { $thread->{pt_execute} = OWX_ASYNC_PT_Execute($master,1,$owx_dev,$thread->{'select'},16);
PT_EXIT("OWLCD: Device $owx_dev not accessible for reading in 2nd step"); $thread->{TimeoutTime} = gettimeofday()+2; #TODO: implement attribute-based timeout
} PT_WAIT_THREAD($thread->{pt_execute});
PT_WAIT_UNTIL($thread->{ExecuteResponse}); delete $thread->{TimeoutTime};
my $response = $thread->{ExecuteResponse}; die $thread->{pt_execute}->PT_CAUSE() if ($thread->{pt_execute}->PT_STATE() == PT_ERROR);
unless ($response->{success}) {
PT_EXIT("OWLCD: Device $owx_dev error reading memory in 2nd step");
}
OWXLCD_BinValues($hash, "get.memory.$page", 1, 1, $owx_dev, $response->{writedata}, $response->{numread}, $response->{readdata}); OWXLCD_BinValues($hash, "get.memory.$page", 1, 1, $owx_dev, $thread->{'select'}, 16, $thread->{pt_execute}->PT_RETVAL());
#-- process results (10 bytes or more have been sent) #-- process results (10 bytes or more have been sent)
#$res2 = substr($res,11,16); #$res2 = substr($res,11,16);
#return $res2; #return $res2;
PT_END; PT_END;
});
} }
######################################################################################## ########################################################################################
@ -1111,11 +1142,11 @@ sub OWXLCD_InitializeDevice($) {
if ($hash->{ASYNC}) { if ($hash->{ASYNC}) {
eval { eval {
OWX_ASYNC_Schedule($hash,PT_THREAD(\&OWXLCD_PT_Byte),$hash,"register",38); OWX_ASYNC_Schedule($hash,OWXLCD_PT_Byte($hash,"register",38));
OWX_ASYNC_Schedule($hash,PT_THREAD(\&OWXLCD_PT_Byte),$hash,"register", 9); OWX_ASYNC_Schedule($hash,OWXLCD_PT_Byte($hash,"register", 9));
OWX_ASYNC_Schedule($hash,PT_THREAD(\&OWXLCD_PT_Byte),$hash,"register",32); OWX_ASYNC_Schedule($hash,OWXLCD_PT_Byte($hash,"register",32));
OWX_ASYNC_Schedule($hash,PT_THREAD(\&OWXLCD_PT_Byte),$hash,"register",12); OWX_ASYNC_Schedule($hash,OWXLCD_PT_Byte($hash,"register",12));
OWX_ASYNC_Schedule($hash,PT_THREAD(\&OWXLCD_PT_Byte),$hash,"register", 1); OWX_ASYNC_Schedule($hash,OWXLCD_PT_Byte($hash,"register", 1));
}; };
return GP_Catch($@) if $@; return GP_Catch($@) if $@;
} else { } else {
@ -1217,8 +1248,11 @@ sub OWXLCD_SetFunction($$$) {
sub OWXLCD_PT_SetFunction($$$) { sub OWXLCD_PT_SetFunction($$$) {
my ($thread,$hash,$cmd,$value) = @_; my ($hash,$cmd,$value) = @_;
return PT_THREAD(sub {
my ($thread) = @_;
my ($select); my ($select);
#-- ID of the device, hash of the busmaster #-- ID of the device, hash of the busmaster
@ -1259,15 +1293,14 @@ sub OWXLCD_PT_SetFunction($$$) {
return "OWXLCD: Wrong function selected"; return "OWXLCD: Wrong function selected";
} }
#"set.function" #"set.function"
unless (OWX_ASYNC_Execute( $master, $thread, 1, $owx_dev, $select, 0 )) { $thread->{pt_execute} = OWX_ASYNC_PT_Execute($master,1,$owx_dev,$select,0);
PT_EXIT("OWLCD: Device $owx_dev not accessible for writing"); $thread->{TimeoutTime} = gettimeofday()+2; #TODO: implement attribute-based timeout
} PT_WAIT_THREAD($thread->{pt_execute});
PT_WAIT_UNTIL($thread->{ExecuteResponse}); delete $thread->{TimeoutTime};
unless ($thread->{ExecuteResponse}->{success}) { die $thread->{pt_execute}->PT_CAUSE() if ($thread->{pt_execute}->PT_STATE() == PT_ERROR);
PT_EXIT("OWLCD: Device $owx_dev error writing");
}
PT_END; PT_END;
});
} }
######################################################################################## ########################################################################################
@ -1380,8 +1413,11 @@ sub OWXLCD_SetIcon($$$) {
######################################################################################## ########################################################################################
sub OWXLCD_PT_SetIcon($$$) { sub OWXLCD_PT_SetIcon($$$) {
my ($thread,$hash,$icon,$value) = @_; my ($hash,$icon,$value) = @_;
return PT_THREAD(sub {
my ($thread) = @_;
my ($i,$data,$select, $res); my ($i,$data,$select, $res);
#-- ID of the device, hash of the busmaster #-- ID of the device, hash of the busmaster
@ -1398,37 +1434,31 @@ sub OWXLCD_PT_SetIcon($$$) {
#-- 4 bit data size, RE => 1, blink Enable = \x26 #-- 4 bit data size, RE => 1, blink Enable = \x26
$select = "\x10\x26"; $select = "\x10\x26";
#"set.icon.1" #"set.icon.1"
unless (OWX_ASYNC_Execute( $master, $thread, 1, $owx_dev, $select, 0 )) { $thread->{pt_execute} = OWX_ASYNC_PT_Execute($master,1,$owx_dev,$select,0);
PT_EXIT("Device $owx_dev not accessible for writing"); $thread->{TimeoutTime} = gettimeofday()+2; #TODO: implement attribute-based timeout
} PT_WAIT_THREAD($thread->{pt_execute});
PT_WAIT_UNTIL($thread->{ExecuteResponse}); delete $thread->{TimeoutTime};
unless ($thread->{ExecuteResponse}->{success}) { die $thread->{pt_execute}->PT_CAUSE() if ($thread->{pt_execute}->PT_STATE() == PT_ERROR);
PT_EXIT("OWLCD: Device $owx_dev error writing");
}
#-- SEGRAM addres to 0 = \x40, #-- SEGRAM addres to 0 = \x40,
$select = "\x10\x40"; $select = "\x10\x40";
#-- write 16 zeros to scratchpad #-- write 16 zeros to scratchpad
$select .= "\x4E\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"; $select .= "\x4E\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00";
#"set.icon.2" #"set.icon.2"
unless (OWX_ASYNC_Execute( $master, $thread, 1, $owx_dev, $select, 0 )) { $thread->{pt_execute} = OWX_ASYNC_PT_Execute($master,1,$owx_dev,$select,0);
PT_EXIT("Device $owx_dev not accessible for writing"); $thread->{TimeoutTime} = gettimeofday()+2; #TODO: implement attribute-based timeout
} PT_WAIT_THREAD($thread->{pt_execute});
PT_WAIT_UNTIL($thread->{ExecuteResponse}); delete $thread->{TimeoutTime};
unless ($thread->{ExecuteResponse}->{success}) { die $thread->{pt_execute}->PT_CAUSE() if ($thread->{pt_execute}->PT_STATE() == PT_ERROR);
PT_EXIT("OWLCD: Device $owx_dev error writing");
}
#-- issue the copy scratchpad to LCD command \x48 #-- issue the copy scratchpad to LCD command \x48
$select="\x48"; $select="\x48";
#"set.icon.3" #"set.icon.3"
unless (OWX_ASYNC_Execute( $master, $thread, 1, $owx_dev, $select, 0 )) { $thread->{pt_execute} = OWX_ASYNC_PT_Execute($master,1,$owx_dev,$select,0);
PT_EXIT("Device $owx_dev not accessible for writing"); $thread->{TimeoutTime} = gettimeofday()+2; #TODO: implement attribute-based timeout
} PT_WAIT_THREAD($thread->{pt_execute});
PT_WAIT_UNTIL($thread->{ExecuteResponse}); delete $thread->{TimeoutTime};
unless ($thread->{ExecuteResponse}->{success}) { die $thread->{pt_execute}->PT_CAUSE() if ($thread->{pt_execute}->PT_STATE() == PT_ERROR);
PT_EXIT("OWLCD: Device $owx_dev error writing");
}
} else { } else {
#-- determine data value #-- determine data value
if( int($icon) != 16 ){ if( int($icon) != 16 ){
@ -1439,7 +1469,7 @@ sub OWXLCD_PT_SetIcon($$$) {
} elsif ( $value == 2) { } elsif ( $value == 2) {
$data = 80; $data = 80;
} else { } else {
PT_EXIT("OWXLCD: Wrong data value $value for icon $icon"); die("OWXLCD: Wrong data value $value for icon $icon");
} }
} else { } else {
if( $value == 0 ){ if( $value == 0 ){
@ -1457,58 +1487,51 @@ sub OWXLCD_PT_SetIcon($$$) {
} elsif ( $value == 6) { } elsif ( $value == 6) {
$data = 80; $data = 80;
} else { } else {
PT_EXIT("OWXLCD: Wrong data value $value for icon $icon"); die("OWXLCD: Wrong data value $value for icon $icon");
} }
} }
#-- 4 bit data size, RE => 1, blink Enable = \x26 #-- 4 bit data size, RE => 1, blink Enable = \x26
$select = "\x10\x26"; $select = "\x10\x26";
#"set.icon.4" #"set.icon.4"
unless (OWX_ASYNC_Execute( $master, $thread, 1, $owx_dev, $select, 0 )) { $thread->{pt_execute} = OWX_ASYNC_PT_Execute($master,1,$owx_dev,$select,0);
PT_EXIT("Device $owx_dev not accessible for writing"); $thread->{TimeoutTime} = gettimeofday()+2; #TODO: implement attribute-based timeout
} PT_WAIT_THREAD($thread->{pt_execute});
PT_WAIT_UNTIL($thread->{ExecuteResponse}); delete $thread->{TimeoutTime};
unless ($thread->{ExecuteResponse}->{success}) { die $thread->{pt_execute}->PT_CAUSE() if ($thread->{pt_execute}->PT_STATE() == PT_ERROR);
PT_EXIT("OWLCD: Device $owx_dev error writing");
}
#-- SEGRAM addres to 0 = \x40 + icon address #-- SEGRAM addres to 0 = \x40 + icon address
$select = sprintf("\x10%c",63+$icon); $select = sprintf("\x10%c",63+$icon);
#"set.icon.5" #"set.icon.5"
unless (OWX_ASYNC_Execute( $master, $thread, 1, $owx_dev, $select, 0 )) { $thread->{pt_execute} = OWX_ASYNC_PT_Execute($master,1,$owx_dev,$select,0);
PT_EXIT("Device $owx_dev not accessible for writing"); $thread->{TimeoutTime} = gettimeofday()+2; #TODO: implement attribute-based timeout
} PT_WAIT_THREAD($thread->{pt_execute});
PT_WAIT_UNTIL($thread->{ExecuteResponse}); delete $thread->{TimeoutTime};
unless ($thread->{ExecuteResponse}->{success}) { die $thread->{pt_execute}->PT_CAUSE() if ($thread->{pt_execute}->PT_STATE() == PT_ERROR);
PT_EXIT("OWLCD: Device $owx_dev error writing");
}
#-- data #-- data
$select = sprintf("\x12%c",$data); $select = sprintf("\x12%c",$data);
#"set.icon.6" #"set.icon.6"
unless (OWX_ASYNC_Execute( $master, $thread, 1, $owx_dev, $select, 0 )) { $thread->{pt_execute} = OWX_ASYNC_PT_Execute($master,1,$owx_dev,$select,0);
PT_EXIT("Device $owx_dev not accessible for writing"); $thread->{TimeoutTime} = gettimeofday()+2; #TODO: implement attribute-based timeout
} PT_WAIT_THREAD($thread->{pt_execute});
PT_WAIT_UNTIL($thread->{ExecuteResponse}); delete $thread->{TimeoutTime};
unless ($thread->{ExecuteResponse}->{success}) { die $thread->{pt_execute}->PT_CAUSE() if ($thread->{pt_execute}->PT_STATE() == PT_ERROR);
PT_EXIT("OWLCD: Device $owx_dev error writing");
}
} }
#-- return to normal state #-- return to normal state
$select = "\x10\x20"; $select = "\x10\x20";
#"set.icon.7" #"set.icon.7"
unless (OWX_ASYNC_Execute( $master, $thread, 1, $owx_dev, $select, 0 )) { $thread->{pt_execute} = OWX_ASYNC_PT_Execute($master,1,$owx_dev,$select,0);
PT_EXIT("Device $owx_dev not accessible for writing"); $thread->{TimeoutTime} = gettimeofday()+2; #TODO: implement attribute-based timeout
} PT_WAIT_THREAD($thread->{pt_execute});
PT_WAIT_UNTIL($thread->{ExecuteResponse}); delete $thread->{TimeoutTime};
unless ($thread->{ExecuteResponse}->{success}) { die $thread->{pt_execute}->PT_CAUSE() if ($thread->{pt_execute}->PT_STATE() == PT_ERROR);
PT_EXIT("OWLCD: Device $owx_dev error writing");
}
#-- or else #-- or else
} else { } else {
PT_EXIT("OWXLCD: Wrong LCD controller type"); die("OWXLCD: Wrong LCD controller type");
} }
PT_END; PT_END;
});
} }
######################################################################################## ########################################################################################
@ -1609,8 +1632,11 @@ sub OWXLCD_SetLine($$$) {
sub OWXLCD_PT_SetLine($$$) { sub OWXLCD_PT_SetLine($$$) {
my ($thread,$hash,$line,$msg) = @_; my ($hash,$line,$msg) = @_;
return PT_THREAD(sub {
my ($thread) = @_;
my ($select, $i, $msgA, $msgB); my ($select, $i, $msgA, $msgB);
#-- ID of the device, hash of the busmaster #-- ID of the device, hash of the busmaster
@ -1655,24 +1681,20 @@ sub OWXLCD_PT_SetLine($$$) {
# followed by LCD page address and the text # followed by LCD page address and the text
$select=sprintf("\x4E%c",$lcdpage[$line]).$msgA; $select=sprintf("\x4E%c",$lcdpage[$line]).$msgA;
#"set.line.1" #"set.line.1"
unless (OWX_ASYNC_Execute( $master, $thread, 1, $owx_dev, $select, 0 )) { $thread->{pt_execute} = OWX_ASYNC_PT_Execute($master,1,$owx_dev,$select,0);
PT_EXIT("Device $owx_dev not accessible for writing"); $thread->{TimeoutTime} = gettimeofday()+2; #TODO: implement attribute-based timeout
} PT_WAIT_THREAD($thread->{pt_execute});
PT_WAIT_UNTIL($thread->{ExecuteResponse}); delete $thread->{TimeoutTime};
unless ($thread->{ExecuteResponse}->{success}) { die $thread->{pt_execute}->PT_CAUSE() if ($thread->{pt_execute}->PT_STATE() == PT_ERROR);
PT_EXIT("OWLCD: Device $owx_dev error writing");
}
#-- issue the copy scratchpad to LCD command \x48 #-- issue the copy scratchpad to LCD command \x48
$select="\x48"; $select="\x48";
#"set.line.2" #"set.line.2"
unless (OWX_ASYNC_Execute( $master, $thread, 1, $owx_dev, $select, 0 )) { $thread->{pt_execute} = OWX_ASYNC_PT_Execute($master,1,$owx_dev,$select,0);
PT_EXIT("Device $owx_dev not accessible for writing"); $thread->{TimeoutTime} = gettimeofday()+2; #TODO: implement attribute-based timeout
} PT_WAIT_THREAD($thread->{pt_execute});
PT_WAIT_UNTIL($thread->{ExecuteResponse}); delete $thread->{TimeoutTime};
unless ($thread->{ExecuteResponse}->{success}) { die $thread->{pt_execute}->PT_CAUSE() if ($thread->{pt_execute}->PT_STATE() == PT_ERROR);
PT_EXIT("OWLCD: Device $owx_dev error writing");
}
#-- if second string available: #-- if second string available:
if( defined($thread->{msgB}) ) { if( defined($thread->{msgB}) ) {
@ -1681,26 +1703,23 @@ sub OWXLCD_PT_SetLine($$$) {
# followed by LCD page address and the text # followed by LCD page address and the text
$select=sprintf("\x4E%c",$lcdpage[$line]+16).$thread->{msgB}; $select=sprintf("\x4E%c",$lcdpage[$line]+16).$thread->{msgB};
#"set.line.3" #"set.line.3"
unless (OWX_ASYNC_Execute( $master, $thread, 1, $owx_dev, $select, 0 )) { $thread->{pt_execute} = OWX_ASYNC_PT_Execute($master,1,$owx_dev,$select,0);
PT_EXIT("Device $owx_dev not accessible for writing"); $thread->{TimeoutTime} = gettimeofday()+2; #TODO: implement attribute-based timeout
} PT_WAIT_THREAD($thread->{pt_execute});
PT_WAIT_UNTIL($thread->{ExecuteResponse}); delete $thread->{TimeoutTime};
unless ($thread->{ExecuteResponse}->{success}) { die $thread->{pt_execute}->PT_CAUSE() if ($thread->{pt_execute}->PT_STATE() == PT_ERROR);
PT_EXIT("OWLCD: Device $owx_dev error writing");
}
#-- issue the copy scratchpad to LCD command \x48 #-- issue the copy scratchpad to LCD command \x48
$select="\x48"; $select="\x48";
#"set.line.4" #"set.line.4"
unless (OWX_ASYNC_Execute( $master, $thread, 1, $owx_dev, $select, 0 )) { $thread->{pt_execute} = OWX_ASYNC_PT_Execute($master,1,$owx_dev,$select,0);
PT_EXIT("Device $owx_dev not accessible for writing"); $thread->{TimeoutTime} = gettimeofday()+2; #TODO: implement attribute-based timeout
} PT_WAIT_THREAD($thread->{pt_execute});
PT_WAIT_UNTIL($thread->{ExecuteResponse}); delete $thread->{TimeoutTime};
unless ($thread->{ExecuteResponse}->{success}) { die $thread->{pt_execute}->PT_CAUSE() if ($thread->{pt_execute}->PT_STATE() == PT_ERROR);
PT_EXIT("OWLCD: Device $owx_dev error writing");
}
} }
PT_END; PT_END;
});
} }
######################################################################################## ########################################################################################
@ -1794,8 +1813,11 @@ sub OWXLCD_SetMemory($$$) {
sub OWXLCD_PT_SetMemory($$$) { sub OWXLCD_PT_SetMemory($$$) {
my ($thread,$hash,$page,$msg) = @_; my ($hash,$page,$msg) = @_;
return PT_THREAD(sub {
my ($thread,$hash,$page,$msg) = @_;
my ($select, $i, $msgA); my ($select, $i, $msgA);
#-- ID of the device, hash of the busmaster #-- ID of the device, hash of the busmaster
@ -1818,25 +1840,22 @@ sub OWXLCD_PT_SetMemory($$$) {
#Log 1," page written is ".$page; #Log 1," page written is ".$page;
$select=sprintf("\x4E\%c",$page).$msgA; $select=sprintf("\x4E\%c",$page).$msgA;
#"set.memory.page" #"set.memory.page"
unless (OWX_ASYNC_Execute( $master, $thread, 1, $owx_dev, $select, 0 )) { $thread->{pt_execute} = OWX_ASYNC_PT_Execute($master,1,$owx_dev,$select,0);
PT_EXIT("Device $owx_dev not accessible for writing"); $thread->{TimeoutTime} = gettimeofday()+2; #TODO: implement attribute-based timeout
} PT_WAIT_THREAD($thread->{pt_execute});
PT_WAIT_UNTIL($thread->{ExecuteResponse}); delete $thread->{TimeoutTime};
unless ($thread->{ExecuteResponse}->{success}) { die $thread->{pt_execute}->PT_CAUSE() if ($thread->{pt_execute}->PT_STATE() == PT_ERROR);
PT_EXIT("OWLCD: Device $owx_dev error writing");
}
#-- issue the copy scratchpad to EEPROM command \x39 #-- issue the copy scratchpad to EEPROM command \x39
$select = "\x39"; $select = "\x39";
#"set.memory.copy" #"set.memory.copy"
unless (OWX_ASYNC_Execute( $master, $thread, 1, $owx_dev, $select, 0 )) { $thread->{pt_execute} = OWX_ASYNC_PT_Execute($master,1,$owx_dev,$select,0);
PT_EXIT("Device $owx_dev not accessible for writing"); $thread->{TimeoutTime} = gettimeofday()+2; #TODO: implement attribute-based timeout
} PT_WAIT_THREAD($thread->{pt_execute});
PT_WAIT_UNTIL($thread->{ExecuteResponse}); delete $thread->{TimeoutTime};
unless ($thread->{ExecuteResponse}->{success}) { die $thread->{pt_execute}->PT_CAUSE() if ($thread->{pt_execute}->PT_STATE() == PT_ERROR);
PT_EXIT("OWLCD: Device $owx_dev error writing");
}
PT_END; PT_END;
});
} }
sub OWXLCD_BinValues($$$$$$$$) { sub OWXLCD_BinValues($$$$$$$$) {

View File

@ -82,7 +82,7 @@ no warnings 'deprecated';
sub Log($$); sub Log($$);
my $owx_version="5.15"; my $owx_version="5.16";
#-- flexible channel name #-- flexible channel name
my $owg_channel; my $owg_channel;
@ -130,6 +130,8 @@ sub OWMULTI_Initialize ($) {
$hash->{UndefFn} = "OWMULTI_Undef"; $hash->{UndefFn} = "OWMULTI_Undef";
$hash->{GetFn} = "OWMULTI_Get"; $hash->{GetFn} = "OWMULTI_Get";
$hash->{SetFn} = "OWMULTI_Set"; $hash->{SetFn} = "OWMULTI_Set";
$hash->{NotifyFn}= "OWMULTI_Notify";
$hash->{InitFn} = "OWMULTI_Init";
$hash->{AttrFn} = "OWMULTI_Attr"; $hash->{AttrFn} = "OWMULTI_Attr";
#tempOffset = a temperature offset added to the temperature reading for correction #tempOffset = a temperature offset added to the temperature reading for correction
@ -182,6 +184,9 @@ sub OWMULTI_Attr(@) {
AssignIoPort($hash,$value); AssignIoPort($hash,$value);
if( defined($hash->{IODev}) ) { if( defined($hash->{IODev}) ) {
$hash->{ASYNC} = $hash->{IODev}->{TYPE} eq "OWX_ASYNC" ? 1 : 0; $hash->{ASYNC} = $hash->{IODev}->{TYPE} eq "OWX_ASYNC" ? 1 : 0;
if ($init_done) {
OWMULTI_Init($hash);
}
} }
last; last;
}; };
@ -277,9 +282,29 @@ sub OWMULTI_Define ($$) {
readingsSingleUpdate($hash,"state","defined",1); readingsSingleUpdate($hash,"state","defined",1);
Log 3, "OWMULTI: Device $name defined."; Log 3, "OWMULTI: Device $name defined.";
#-- Start timer for updates $hash->{NOTIFYDEV} = "global";
InternalTimer(time()+10, "OWMULTI_GetValues", $hash, 0);
if ($init_done) {
OWMULTI_Init($hash);
}
return undef;
}
sub OWMULTI_Notify ($$) {
my ($hash,$dev) = @_;
if( grep(m/^(INITIALIZED|REREADCFG)$/, @{$dev->{CHANGED}}) ) {
OWMULTI_Init($hash);
} elsif( grep(m/^SAVE$/, @{$dev->{CHANGED}}) ) {
}
}
sub OWMULTI_Init ($) {
my ($hash)=@_;
#-- Start timer for updates
RemoveInternalTimer($hash);
InternalTimer(gettimeofday()+10, "OWMULTI_GetValues", $hash, 0);
#--
readingsSingleUpdate($hash,"state","Initialized",1);
return undef; return undef;
} }
@ -445,6 +470,8 @@ sub OWMULTI_Get($@) {
return "$name.id => $value"; return "$name.id => $value";
} }
#-- hash of the busmaster
my $master = $hash->{IODev};
#-- Get other values according to interface type #-- Get other values according to interface type
my $interface= $hash->{IODev}->{TYPE}; my $interface= $hash->{IODev}->{TYPE};
@ -452,11 +479,17 @@ sub OWMULTI_Get($@) {
if($a[1] eq "present" ) { if($a[1] eq "present" ) {
#-- OWX interface #-- OWX interface
if( $interface =~ /^OWX/ ){ if( $interface =~ /^OWX/ ){
#-- hash of the busmaster
my $master = $hash->{IODev};
#-- asynchronous mode #-- asynchronous mode
if( $hash->{ASYNC} ){ if( $hash->{ASYNC} ){
$value = OWX_ASYNC_Verify($master,$hash->{ROM_ID}); my ($task,$task_state);
eval {
$task = OWX_ASYNC_PT_Verify($hash);
OWX_ASYNC_Schedule($hash,$task);
$task_state = OWX_ASYNC_RunToCompletion($master,$task);
};
return GP_Catch($@) if $@;
return $task->PT_CAUSE() if ($task_state == PT_ERROR or $task_state == PT_CANCELED);
return "$name.present => ".ReadingsVal($name,"present","unknown");
} else { } else {
$value = OWX_Verify($master,$hash->{ROM_ID}); $value = OWX_Verify($master,$hash->{ROM_ID});
} }
@ -484,12 +517,13 @@ sub OWMULTI_Get($@) {
#-- not different from getting all values .. #-- not different from getting all values ..
$ret = OWXMULTI_GetValues($hash); $ret = OWXMULTI_GetValues($hash);
}elsif( $interface eq "OWX_ASYNC"){ }elsif( $interface eq "OWX_ASYNC"){
#TODO use OWX_ASYNC_Schedule instead my ($task,$task_state);
my $task = PT_THREAD(\&OWXMULTI_PT_GetValues);
eval { eval {
while ($task->PT_SCHEDULE($hash)) { OWX_ASYNC_Poll($hash->{IODev}); }; $task = OWXMULTI_PT_GetValues($hash);
OWX_ASYNC_Schedule($hash,$task);
$task_state = OWX_ASYNC_RunToCompletion($master,$task);
}; };
$ret = ($@) ? GP_Catch($@) : $task->PT_RETVAL(); $ret = ($@) ? GP_Catch($@) : ($task_state == PT_ERROR or $task_state == PT_CANCELED) ? $task->PT_CAUSE() : $task->PT_RETVAL();
#-- OWFS interface not yet implemented #-- OWFS interface not yet implemented
}elsif( $interface eq "OWServer" ){ }elsif( $interface eq "OWServer" ){
$ret = OWFSMULTI_GetValues($hash); $ret = OWFSMULTI_GetValues($hash);
@ -558,7 +592,7 @@ sub OWMULTI_GetValues($) {
} }
}elsif( $interface eq "OWX_ASYNC" ){ }elsif( $interface eq "OWX_ASYNC" ){
eval { eval {
OWX_ASYNC_Schedule( $hash, PT_THREAD(\&OWXMULTI_PT_GetValues),$hash ); OWX_ASYNC_Schedule( $hash, OWXMULTI_PT_GetValues($hash) );
}; };
$ret = GP_Catch($@) if $@; $ret = GP_Catch($@) if $@;
}elsif( $interface eq "OWServer" ){ }elsif( $interface eq "OWServer" ){
@ -656,7 +690,7 @@ sub OWMULTI_Set($@) {
$ret = OWXMULTI_SetValues($hash,@a); $ret = OWXMULTI_SetValues($hash,@a);
}elsif( $interface eq "OWX_ASYNC" ){ }elsif( $interface eq "OWX_ASYNC" ){
eval { eval {
OWX_ASYNC_Schedule( $hash, PT_THREAD(\&OWXMULTI_PT_SetValues),$hash,@a ); OWX_ASYNC_Schedule( $hash, OWXMULTI_PT_SetValues($hash,@a) );
}; };
$ret = GP_Catch($@) if $@; $ret = GP_Catch($@) if $@;
#-- OWFS interface #-- OWFS interface
@ -1013,7 +1047,11 @@ sub OWXMULTI_SetValues($@) {
sub OWXMULTI_PT_GetValues($) { sub OWXMULTI_PT_GetValues($) {
my ($thread,$hash) = @_; my ($hash) = @_;
return PT_THREAD(sub {
my ($thread) = @_;
my ($i,$j,$k,$res,$ret,$response); my ($i,$j,$k,$res,$ret,$response);
@ -1023,163 +1061,152 @@ sub OWXMULTI_PT_GetValues($) {
my $master = $hash->{IODev}; my $master = $hash->{IODev};
PT_BEGIN($thread); PT_BEGIN($thread);
#-- reset presence
$hash->{PRESENT} = 0;
#------------------------------------------------------------------------------------ #------------------------------------------------------------------------------------
#-- switch the device to current measurement off, VDD only #-- switch the device to current measurement off, VDD only
#-- issue the match ROM command \x55 and the write scratchpad command #-- issue the match ROM command \x55 and the write scratchpad command
#"ds2438.writestatusvdd" #"ds2438.writestatusvdd"
unless (OWX_ASYNC_Execute( $master, $thread, 1, $owx_dev, "\x4E\x00\x08", 0)) { $thread->{pt_execute} = OWX_ASYNC_PT_Execute($master,1,$owx_dev,"\x4E\x00\x08",0);
PT_EXIT("$owx_dev not accessible for writing status"); $thread->{TimeoutTime} = gettimeofday()+2; #TODO: implement attribute-based timeout
} PT_WAIT_THREAD($thread->{pt_execute});
PT_WAIT_UNTIL($thread->{ExecuteResponse}); delete $thread->{TimeoutTime};
unless ($thread->{ExecuteResponse}->{success}) { die $thread->{pt_execute}->PT_CAUSE() if ($thread->{pt_execute}->PT_STATE() == PT_ERROR);
PT_EXIT("$owx_dev write status failed");
}
#-- copy scratchpad to register #-- copy scratchpad to register
#-- issue the match ROM command \x55 and the copy scratchpad command #-- issue the match ROM command \x55 and the copy scratchpad command
#"ds2438.copyscratchpadvdd" #"ds2438.copyscratchpadvdd"
unless (OWX_ASYNC_Execute( $master, $thread, 1, $owx_dev, "\x48\x00", 0)) { $thread->{pt_execute} = OWX_ASYNC_PT_Execute($master,1,$owx_dev,"\x48\x00",0);
PT_EXIT("$owx_dev not accessible to copy scratchpad"); $thread->{TimeoutTime} = gettimeofday()+2; #TODO: implement attribute-based timeout
} PT_WAIT_THREAD($thread->{pt_execute});
PT_WAIT_UNTIL($thread->{ExecuteResponse}); delete $thread->{TimeoutTime};
unless ($thread->{ExecuteResponse}->{success}) { die $thread->{pt_execute}->PT_CAUSE() if ($thread->{pt_execute}->PT_STATE() == PT_ERROR);
PT_EXIT("$owx_dev copy scratchpad failed");
}
#-- initiate temperature conversion #-- initiate temperature conversion
#-- conversion needs some 12 ms ! #-- conversion needs some 12 ms !
#-- issue the match ROM command \x55 and the start conversion command #-- issue the match ROM command \x55 and the start conversion command
#"ds2438.temperaturconversionvdd" #"ds2438.temperaturconversionvdd"
unless (OWX_ASYNC_Execute( $master, $thread, 1, $owx_dev, "\x44", 0)) { $thread->{pt_execute} = OWX_ASYNC_PT_Execute($master,1,$owx_dev,"\x44",0);
PT_EXIT("$owx_dev not accessible for temperature conversion"); $thread->{TimeoutTime} = gettimeofday()+2; #TODO: implement attribute-based timeout
} PT_WAIT_THREAD($thread->{pt_execute});
PT_WAIT_UNTIL($thread->{ExecuteResponse}); delete $thread->{TimeoutTime};
unless ($thread->{ExecuteResponse}->{success}) { die $thread->{pt_execute}->PT_CAUSE() if ($thread->{pt_execute}->PT_STATE() == PT_ERROR);
PT_EXIT("$owx_dev temperature conversion failed");
} $thread->{ExecuteTime} = gettimeofday() + 0.012;
#TODO implement async wait PT_YIELD_UNTIL(gettimeofday() >= $thread->{ExecuteTime});
select(undef,undef,undef,0.012); delete $thread->{ExecuteTime};
#-- initiate voltage conversion #-- initiate voltage conversion
#-- conversion needs some 6 ms ! #-- conversion needs some 6 ms !
#-- issue the match ROM command \x55 and the start conversion command #-- issue the match ROM command \x55 and the start conversion command
#"ds2438.voltageconversionvdd" #"ds2438.voltageconversionvdd"
unless (OWX_ASYNC_Execute( $master, $thread, 1, $owx_dev, "\xB4", 0)) { $thread->{pt_execute} = OWX_ASYNC_PT_Execute($master,1,$owx_dev,"\xB4",0);
PT_EXIT("$owx_dev not accessible for voltage conversion"); $thread->{TimeoutTime} = gettimeofday()+2; #TODO: implement attribute-based timeout
} PT_WAIT_THREAD($thread->{pt_execute});
PT_WAIT_UNTIL($thread->{ExecuteResponse}); delete $thread->{TimeoutTime};
unless ($thread->{ExecuteResponse}->{success}) { die $thread->{pt_execute}->PT_CAUSE() if ($thread->{pt_execute}->PT_STATE() == PT_ERROR);
PT_EXIT("$owx_dev voltage conversion failed");
} $thread->{ExecuteTime} = gettimeofday() + 0.006;
#TODO implement async wait PT_YIELD_UNTIL(gettimeofday() >= $thread->{ExecuteTime});
select(undef,undef,undef,0.006); delete $thread->{ExecuteTime};
#-- from memory to scratchpad #-- from memory to scratchpad
#-- copy needs some 12 ms ! #-- copy needs some 12 ms !
#-- issue the match ROM command \x55 and the recall memory command #-- issue the match ROM command \x55 and the recall memory command
#"ds2438.recallmemoryvdd" #"ds2438.recallmemoryvdd"
unless (OWX_ASYNC_Execute( $master, $thread, 1, $owx_dev, "\xB8\x00", 0)) { $thread->{pt_execute} = OWX_ASYNC_PT_Execute($master,1,$owx_dev,"\xB8\x00",0);
PT_EXIT("$owx_dev not accessible for recall memory"); $thread->{TimeoutTime} = gettimeofday()+2; #TODO: implement attribute-based timeout
} PT_WAIT_THREAD($thread->{pt_execute});
PT_WAIT_UNTIL($thread->{ExecuteResponse}); delete $thread->{TimeoutTime};
unless ($thread->{ExecuteResponse}->{success}) { die $thread->{pt_execute}->PT_CAUSE() if ($thread->{pt_execute}->PT_STATE() == PT_ERROR);
PT_EXIT("$owx_dev recall memory failed");
} $thread->{ExecuteTime} = gettimeofday() + 0.012;
#TODO implement async wait PT_YIELD_UNTIL(gettimeofday() >= $thread->{ExecuteTime});
select(undef,undef,undef,0.012); delete $thread->{ExecuteTime};
#-- NOW ask the specific device #-- NOW ask the specific device
#-- issue the match ROM command \x55 and the read scratchpad command \xBE #-- issue the match ROM command \x55 and the read scratchpad command \xBE
#-- reading 9 + 2 + 9 data bytes = 20 bytes #-- reading 9 + 2 + 9 data bytes = 20 bytes
#"ds2438.getvdd" #"ds2438.getvdd"
unless (OWX_ASYNC_Execute( $master, $thread, 1, $owx_dev, "\xBE\x00", 9)) { $thread->{pt_execute} = OWX_ASYNC_PT_Execute($master,1,$owx_dev,"\xBE\x00",9);
PT_EXIT("$owx_dev not accessible in 2nd step"); $thread->{TimeoutTime} = gettimeofday()+2; #TODO: implement attribute-based timeout
} PT_WAIT_THREAD($thread->{pt_execute});
PT_WAIT_UNTIL($thread->{ExecuteResponse}); delete $thread->{TimeoutTime};
$response = $thread->{ExecuteResponse}; die $thread->{pt_execute}->PT_CAUSE() if ($thread->{pt_execute}->PT_STATE() == PT_ERROR);
unless ($response->{success}) { $res = $thread->{pt_execute}->PT_RETVAL();
PT_EXIT("$owx_dev not accessible in 2nd step");
}
$res = $response->{readdata};
unless (defined $res and length($res)==9) { unless (defined $res and length($res)==9) {
PT_EXIT("$owx_dev has returned invalid data"); PT_EXIT("$owx_dev has returned invalid data");
} }
$ret = OWXMULTI_BinValues($hash,"ds2438.getvdd",1,undef,$owx_dev,undef,undef,$res); $ret = OWXMULTI_BinValues($hash,"ds2438.getvdd",1,undef,$owx_dev,undef,undef,$res);
if (defined $ret) { if ($ret) {
PT_EXIT($ret); die $ret;
} }
#------------------------------------------------------------------------------------ #------------------------------------------------------------------------------------
#-- switch the device to current measurement off, V external only #-- switch the device to current measurement off, V external only
#-- issue the match ROM command \x55 and the write scratchpad command #-- issue the match ROM command \x55 and the write scratchpad command
#"ds2438.writestatusvad" #"ds2438.writestatusvad"
unless (OWX_ASYNC_Execute( $master, $thread, 1, $owx_dev, "\x4E\x00\x00", 0)) { $thread->{pt_execute} = OWX_ASYNC_PT_Execute($master,1,$owx_dev,"\x4E\x00\x00",0);
PT_EXIT("$owx_dev not accessible to write status"); $thread->{TimeoutTime} = gettimeofday()+2; #TODO: implement attribute-based timeout
} PT_WAIT_THREAD($thread->{pt_execute});
PT_WAIT_UNTIL($thread->{ExecuteResponse}); delete $thread->{TimeoutTime};
unless ($thread->{ExecuteResponse}->{success}) { die $thread->{pt_execute}->PT_CAUSE() if ($thread->{pt_execute}->PT_STATE() == PT_ERROR);
PT_EXIT("$owx_dev write status failed");
}
#-- copy scratchpad to register #-- copy scratchpad to register
#-- issue the match ROM command \x55 and the copy scratchpad command #-- issue the match ROM command \x55 and the copy scratchpad command
#"ds2438.copyscratchpadvad" #"ds2438.copyscratchpadvad"
unless (OWX_ASYNC_Execute( $master, $thread, 1, $owx_dev, "\x48\x00", 0)) { $thread->{pt_execute} = OWX_ASYNC_PT_Execute($master,1,$owx_dev,"\x48\x00",0);
PT_EXIT("$owx_dev not accessible to copy scratchpad"); $thread->{TimeoutTime} = gettimeofday()+2; #TODO: implement attribute-based timeout
} PT_WAIT_THREAD($thread->{pt_execute});
PT_WAIT_UNTIL($thread->{ExecuteResponse}); delete $thread->{TimeoutTime};
unless ($thread->{ExecuteResponse}->{success}) { die $thread->{pt_execute}->PT_CAUSE() if ($thread->{pt_execute}->PT_STATE() == PT_ERROR);
PT_EXIT("$owx_dev copy scratchpad failed");
}
#-- initiate voltage conversion #-- initiate voltage conversion
#-- conversion needs some 6 ms ! #-- conversion needs some 6 ms !
#-- issue the match ROM command \x55 and the start conversion command #-- issue the match ROM command \x55 and the start conversion command
#"ds2438.voltageconversionvad" #"ds2438.voltageconversionvad"
unless (OWX_ASYNC_Execute( $master, $thread, 1, $owx_dev, "\xB4", 0)) { $thread->{pt_execute} = OWX_ASYNC_PT_Execute($master,1,$owx_dev,"\xB4",0);
PT_EXIT("$owx_dev not accessible for voltage conversion"); $thread->{TimeoutTime} = gettimeofday()+2; #TODO: implement attribute-based timeout
} PT_WAIT_THREAD($thread->{pt_execute});
PT_WAIT_UNTIL($thread->{ExecuteResponse}); delete $thread->{TimeoutTime};
unless ($thread->{ExecuteResponse}->{success}) { die $thread->{pt_execute}->PT_CAUSE() if ($thread->{pt_execute}->PT_STATE() == PT_ERROR);
PT_EXIT("$owx_dev voltage conversion failed");
} $thread->{ExecuteTime} = gettimeofday() + 0.006;
#TODO implement async wait PT_YIELD_UNTIL(gettimeofday() >= $thread->{ExecuteTime});
select(undef,undef,undef,0.006); delete $thread->{ExecuteTime};
#-- from memory to scratchpad #-- from memory to scratchpad
#-- copy needs some 12 ms ! #-- copy needs some 12 ms !
#-- issue the match ROM command \x55 and the recall memory command #-- issue the match ROM command \x55 and the recall memory command
#"ds2438.recallmemoryvad" #"ds2438.recallmemoryvad"
unless (OWX_ASYNC_Execute( $master, $thread, 1, $owx_dev, "\xB8\x00", 0)) { $thread->{pt_execute} = OWX_ASYNC_PT_Execute($master,1,$owx_dev,"\xB8\x00",0);
PT_EXIT("$owx_dev not accessible to recall memory"); $thread->{TimeoutTime} = gettimeofday()+2; #TODO: implement attribute-based timeout
} PT_WAIT_THREAD($thread->{pt_execute});
PT_WAIT_UNTIL($thread->{ExecuteResponse}); delete $thread->{TimeoutTime};
unless ($thread->{ExecuteResponse}->{success}) { die $thread->{pt_execute}->PT_CAUSE() if ($thread->{pt_execute}->PT_STATE() == PT_ERROR);
PT_EXIT("$owx_dev recall memory failed");
} $thread->{ExecuteTime} = gettimeofday() + 0.012;
#TODO implement async wait PT_YIELD_UNTIL(gettimeofday() >= $thread->{ExecuteTime});
select(undef,undef,undef,0.012); delete $thread->{ExecuteTime};
#-- NOW ask the specific device #-- NOW ask the specific device
#-- issue the match ROM command \x55 and the read scratchpad command \xBE #-- issue the match ROM command \x55 and the read scratchpad command \xBE
#-- reading 9 + 2 + 9 data bytes = 20 bytes #-- reading 9 + 2 + 9 data bytes = 20 bytes
#"ds2438.getvad" #"ds2438.getvad"
unless (OWX_ASYNC_Execute( $master, $thread, 1, $owx_dev, "\xBE\x00", 9)) { $thread->{pt_execute} = OWX_ASYNC_PT_Execute($master,1,$owx_dev,"\xBE\x00", 9);
PT_EXIT("$owx_dev not accessible in 2nd step"); $thread->{TimeoutTime} = gettimeofday()+2; #TODO: implement attribute-based timeout
} PT_WAIT_THREAD($thread->{pt_execute});
PT_WAIT_UNTIL($thread->{ExecuteResponse}); delete $thread->{TimeoutTime};
$response = $thread->{ExecuteResponse}; die $thread->{pt_execute}->PT_CAUSE() if ($thread->{pt_execute}->PT_STATE() == PT_ERROR);
unless ($response->{success}) {
PT_EXIT("$owx_dev not accessible in 2nd step");
}
#-- process results #-- process results
$res = $response->{readdata}; $res = $thread->{pt_execute}->PT_RETVAL();
unless (defined $res and length($res)==9) { unless (defined $res and length($res)==9) {
PT_EXIT("$owx_dev has returned invalid data"); PT_EXIT("$owx_dev has returned invalid data");
} }
$ret = OWXMULTI_BinValues($hash,"ds2438.getvad",1,undef,$owx_dev,undef,undef,$res); $ret = OWXMULTI_BinValues($hash,"ds2438.getvad",1,undef,$owx_dev,undef,undef,$res);
if (defined $ret) { if ($ret) {
PT_EXIT($ret); die $ret;
} }
PT_END; PT_END;
});
} }
####################################################################################### #######################################################################################
@ -1192,7 +1219,11 @@ sub OWXMULTI_PT_GetValues($) {
######################################################################################## ########################################################################################
sub OWXMULTI_PT_SetValues($@) { sub OWXMULTI_PT_SetValues($@) {
my ($thread,$hash, @a) = @_; my ($hash, @a) = @_;
return PT_THREAD(sub {
my ($thread) = @_;
my ($i,$j,$k); my ($i,$j,$k);
@ -1217,15 +1248,14 @@ sub OWXMULTI_PT_SetValues($@) {
my $select=sprintf("\x4E%c%c\x48",0,0); my $select=sprintf("\x4E%c%c\x48",0,0);
#"setvalues" #"setvalues"
unless (OWX_ASYNC_Execute( $master, $thread, 1, $owx_dev, $select, 0)) { $thread->{pt_execute} = OWX_ASYNC_PT_Execute($master,1,$owx_dev,$select, 0);
PT_EXIT("OWXMULTI: Device $owx_dev not accessible"); $thread->{TimeoutTime} = gettimeofday()+2; #TODO: implement attribute-based timeout
} PT_WAIT_THREAD($thread->{pt_execute});
PT_WAIT_UNTIL($thread->{ExecuteResponse}); delete $thread->{TimeoutTime};
unless ($thread->{ExecuteResponse}->{success}) { die $thread->{pt_execute}->PT_CAUSE() if ($thread->{pt_execute}->PT_STATE() == PT_ERROR);
PT_EXIT("OWXMULTI: error setting values in $owx_dev");
}
PT_END; PT_END;
});
} }
1; 1;

View File

@ -89,7 +89,7 @@ no warnings 'deprecated';
sub Log($$); sub Log($$);
my $owx_version="5.16"; my $owx_version="5.17";
#-- fixed raw channel name, flexible channel name #-- fixed raw channel name, flexible channel name
my @owg_fixed = ("A","B","C","D","E","F","G","H"); my @owg_fixed = ("A","B","C","D","E","F","G","H");
my @owg_channel = ("A","B","C","D","E","F","G","H"); my @owg_channel = ("A","B","C","D","E","F","G","H");
@ -144,6 +144,8 @@ sub OWSWITCH_Initialize ($) {
$hash->{UndefFn} = "OWSWITCH_Undef"; $hash->{UndefFn} = "OWSWITCH_Undef";
$hash->{GetFn} = "OWSWITCH_Get"; $hash->{GetFn} = "OWSWITCH_Get";
$hash->{SetFn} = "OWSWITCH_Set"; $hash->{SetFn} = "OWSWITCH_Set";
$hash->{NotifyFn}= "OWSWITCH_Notify";
$hash->{InitFn} = "OWSWITCH_Init";
$hash->{AttrFn} = "OWSWITCH_Attr"; $hash->{AttrFn} = "OWSWITCH_Attr";
my $attlist = "IODev do_not_notify:0,1 showtime:0,1 model:DS2413,DS2406,DS2408 loglevel:0,1,2,3,4,5 ". my $attlist = "IODev do_not_notify:0,1 showtime:0,1 model:DS2413,DS2406,DS2408 loglevel:0,1,2,3,4,5 ".
@ -266,9 +268,29 @@ sub OWSWITCH_Define ($$) {
readingsSingleUpdate($hash,"state","defined",1); readingsSingleUpdate($hash,"state","defined",1);
Log 3, "OWSWITCH: Device $name defined."; Log 3, "OWSWITCH: Device $name defined.";
#-- Start timer for updates $hash->{NOTIFYDEV} = "global";
InternalTimer(time()+10, "OWSWITCH_GetValues", $hash, 0);
if ($init_done) {
OWSWITCH_Init($hash);
}
return undef;
}
sub OWSWITCH_Notify ($$) {
my ($hash,$dev) = @_;
if( grep(m/^(INITIALIZED|REREADCFG)$/, @{$dev->{CHANGED}}) ) {
OWSWITCH_Init($hash);
} elsif( grep(m/^SAVE$/, @{$dev->{CHANGED}}) ) {
}
}
sub OWSWITCH_Init ($) {
my ($hash)=@_;
#-- Start timer for updates
RemoveInternalTimer($hash);
InternalTimer(gettimeofday()+10, "OWSWITCH_GetValues", $hash, 0);
#--
readingsSingleUpdate($hash,"state","Initialized",1);
return undef; return undef;
} }
@ -307,6 +329,9 @@ sub OWSWITCH_Attr(@) {
AssignIoPort($hash,$value); AssignIoPort($hash,$value);
if( defined($hash->{IODev}) ) { if( defined($hash->{IODev}) ) {
$hash->{ASYNC} = $hash->{IODev}->{TYPE} eq "OWX_ASYNC" ? 1 : 0; $hash->{ASYNC} = $hash->{IODev}->{TYPE} eq "OWX_ASYNC" ? 1 : 0;
if ($init_done) {
OWSWITCH_Init($hash);
}
} }
last; last;
}; };
@ -457,13 +482,22 @@ sub OWSWITCH_Get($@) {
return "$name.id => $value"; return "$name.id => $value";
} }
#-- get present
if($a[1] eq "present") {
#-- hash of the busmaster #-- hash of the busmaster
my $master = $hash->{IODev}; my $master = $hash->{IODev};
#-- get present
if($a[1] eq "present") {
#-- asynchronous mode #-- asynchronous mode
if( $hash->{ASYNC} ){ if( $hash->{ASYNC} ){
$value = OWX_ASYNC_Verify($master,$hash->{ROM_ID}); my ($task,$task_state);
eval {
$task = OWX_ASYNC_PT_Verify($hash);
OWX_ASYNC_Schedule($hash,$task);
$task_state = OWX_ASYNC_RunToCompletion($master,$task);
};
return GP_Catch($@) if $@;
return $task->PT_CAUSE() if ($task_state == PT_ERROR or $task_state == PT_CANCELED);
return "$name.present => ".ReadingsVal($name,"present","unknown");
} else { } else {
$value = OWX_Verify($master,$hash->{ROM_ID}); $value = OWX_Verify($master,$hash->{ROM_ID});
} }
@ -506,12 +540,13 @@ sub OWSWITCH_Get($@) {
if( $interface eq "OWX" ){ if( $interface eq "OWX" ){
$ret = OWXSWITCH_GetState($hash); $ret = OWXSWITCH_GetState($hash);
}elsif( $interface eq "OWX_ASYNC") { }elsif( $interface eq "OWX_ASYNC") {
#TODO use OWX_ASYNC_Schedule instead my ($task,$task_state);
my $task = PT_THREAD(\&OWXSWITCH_PT_GetState);
eval { eval {
while ($task->PT_SCHEDULE($hash)) { OWX_ASYNC_Poll($hash->{IODev}); }; $task = OWXSWITCH_PT_GetState($hash);
OWX_ASYNC_Schedule($hash,$task);
$task_state = OWX_ASYNC_RunToCompletion($master,$task);
}; };
$ret = ($@) ? GP_Catch($@) : $task->PT_RETVAL(); $ret = ($@) ? GP_Catch($@) : ($task_state == PT_ERROR or $task_state == PT_CANCELED) ? $task->PT_CAUSE() : $task->PT_RETVAL();
#-- OWFS interface #-- OWFS interface
}elsif( $interface eq "OWFS" ){ }elsif( $interface eq "OWFS" ){
$ret = OWFSSWITCH_GetState($hash); $ret = OWFSSWITCH_GetState($hash);
@ -530,12 +565,13 @@ sub OWSWITCH_Get($@) {
if( $interface eq "OWX" ){ if( $interface eq "OWX" ){
$ret = OWXSWITCH_GetState($hash); $ret = OWXSWITCH_GetState($hash);
}elsif( $interface eq "OWX_ASYNC" ){ }elsif( $interface eq "OWX_ASYNC" ){
#TODO use OWX_ASYNC_Schedule instead my ($task,$task_state);
my $task = PT_THREAD(\&OWXSWITCH_PT_GetState);
eval { eval {
while ($task->PT_SCHEDULE($hash)) { OWX_ASYNC_Poll($hash->{IODev}); }; $task = OWXSWITCH_PT_GetState($hash);
OWX_ASYNC_Schedule($hash,$task);
$task_state = OWX_ASYNC_RunToCompletion($master,$task);
}; };
$ret = ($@) ? GP_Catch($@) : $task->PT_RETVAL(); $ret = ($@) ? GP_Catch($@) : ($task_state == PT_ERROR or $task_state == PT_CANCELED) ? $task->PT_CAUSE() : $task->PT_RETVAL();
}elsif( $interface eq "OWServer" ){ }elsif( $interface eq "OWServer" ){
$ret = OWFSSWITCH_GetState($hash); $ret = OWFSSWITCH_GetState($hash);
}else{ }else{
@ -583,7 +619,7 @@ sub OWSWITCH_GetValues($) {
} }
}elsif( $interface eq "OWX_ASYNC" ){ }elsif( $interface eq "OWX_ASYNC" ){
eval { eval {
OWX_ASYNC_Schedule( $hash, PT_THREAD(\&OWXSWITCH_PT_GetState),$hash ); OWX_ASYNC_Schedule( $hash, OWXSWITCH_PT_GetState($hash) );
}; };
return unless $@; return unless $@;
$ret = GP_Catch($@); $ret = GP_Catch($@);
@ -753,7 +789,7 @@ sub OWSWITCH_Set($@) {
$ret2 = OWXSWITCH_SetState($hash,$value); $ret2 = OWXSWITCH_SetState($hash,$value);
}elsif( $interface eq "OWX_ASYNC"){ }elsif( $interface eq "OWX_ASYNC"){
eval { eval {
OWX_ASYNC_Schedule( $hash, PT_THREAD(\&OWXSWITCH_PT_SetOutput),$hash,$fnd,$nval ); OWX_ASYNC_Schedule( $hash, OWXSWITCH_PT_SetOutput($hash,$fnd,$nval) );
}; };
$ret2 = GP_Catch($@) if $@; $ret2 = GP_Catch($@) if $@;
#-- OWFS interface #-- OWFS interface
@ -791,7 +827,7 @@ sub OWSWITCH_Set($@) {
$ret = OWXSWITCH_SetState($hash,int($value)); $ret = OWXSWITCH_SetState($hash,int($value));
}elsif( $interface eq "OWX_ASYNC" ){ }elsif( $interface eq "OWX_ASYNC" ){
eval { eval {
OWX_ASYNC_Schedule( $hash, PT_THREAD(\&OWXSWITCH_PT_SetState),$hash,int($value) ); OWX_ASYNC_Schedule( $hash, OWXSWITCH_PT_SetState($hash,int($value)) );
}; };
$ret = GP_Catch($@) if $@; $ret = GP_Catch($@) if $@;
}elsif( $interface eq "OWServer" ){ }elsif( $interface eq "OWServer" ){
@ -1245,8 +1281,12 @@ sub OWXSWITCH_SetState($$) {
######################################################################################## ########################################################################################
sub OWXSWITCH_PT_GetState($) { sub OWXSWITCH_PT_GetState($) {
my ($thread,$hash) = @_;
my ($hash) = @_;
return PT_THREAD( sub {
my ($thread) = @_;
my ($select, $ret, @data, $response); my ($select, $ret, @data, $response);
#-- ID of the device #-- ID of the device
@ -1257,9 +1297,6 @@ sub OWXSWITCH_PT_GetState($) {
PT_BEGIN($thread); PT_BEGIN($thread);
#-- reset presence
$hash->{PRESENT} = 0;
my ($i,$j,$k); my ($i,$j,$k);
#-- family = 12 => DS2406 #-- family = 12 => DS2406
@ -1268,19 +1305,17 @@ sub OWXSWITCH_PT_GetState($) {
#-- issue the match ROM command \x55 and the access channel command #-- issue the match ROM command \x55 and the access channel command
# \xF5 plus the two byte channel control and the value # \xF5 plus the two byte channel control and the value
#-- reading 9 + 3 + 2 data bytes + 2 CRC bytes = 16 bytes #-- reading 9 + 3 + 2 data bytes + 2 CRC bytes = 16 bytes
$select=sprintf("\xF5\xDD\xFF"); $thread->{'select'}=sprintf("\xF5\xDD\xFF");
unless(OWX_ASYNC_Execute( $master, $thread, 1, $owx_dev, $select, 4)) { $thread->{pt_execute} = OWX_ASYNC_PT_Execute($master,1,$owx_dev,$thread->{'select'},4);
PT_EXIT("device $owx_dev not accessible in reading"); $thread->{TimeoutTime} = gettimeofday()+2; #TODO: implement attribute-based timeout
} PT_WAIT_THREAD($thread->{pt_execute});
PT_WAIT_UNTIL(defined $thread->{ExecuteResponse}); delete $thread->{TimeoutTime};
$response = $thread->{ExecuteResponse}; die $thread->{pt_execute}->PT_CAUSE() if ($thread->{pt_execute}->PT_STATE() == PT_ERROR);
unless ($response->{success}) { $response = $thread->{pt_execute}->PT_RETVAL();
unless (length($response) == 4) {
PT_EXIT("$owx_dev has returned invalid data"); PT_EXIT("$owx_dev has returned invalid data");
} }
unless (length($response->{readdata}) == 4) { $ret = OWXSWITCH_BinValues($hash,"ds2406.getstate",1,1,$owx_dev,$thread->{'select'},4,$response);
PT_EXIT("$owx_dev has returned invalid data");
}
$ret = OWXSWITCH_BinValues($hash,"ds2406.getstate",1,1,$owx_dev,$response->{writedata},4,$response->{readdata});
if (defined $ret) { if (defined $ret) {
PT_EXIT($ret); PT_EXIT($ret);
} }
@ -1290,19 +1325,17 @@ sub OWXSWITCH_PT_GetState($) {
#-- issue the match ROM command \x55 and the read PIO rtegisters command #-- issue the match ROM command \x55 and the read PIO rtegisters command
# \xF5 plus the two byte channel target address # \xF5 plus the two byte channel target address
#-- reading 9 + 3 + 8 data bytes + 2 CRC bytes = 22 bytes #-- reading 9 + 3 + 8 data bytes + 2 CRC bytes = 22 bytes
$select=sprintf("\xF0\x88\x00"); $thread->{'select'}=sprintf("\xF0\x88\x00");
unless (OWX_ASYNC_Execute( $master, $thread, 1, $owx_dev, $select, 10)) { $thread->{pt_execute} = OWX_ASYNC_PT_Execute($master,1,$owx_dev,$thread->{'select'},10);
PT_EXIT("device $owx_dev not accessible in reading"); $thread->{TimeoutTime} = gettimeofday()+2; #TODO: implement attribute-based timeout
} PT_WAIT_THREAD($thread->{pt_execute});
PT_WAIT_UNTIL($thread->{ExecuteResponse}); delete $thread->{TimeoutTime};
$response = $thread->{ExecuteResponse}; die $thread->{pt_execute}->PT_CAUSE() if ($thread->{pt_execute}->PT_STATE() == PT_ERROR);
unless ($response->{success}) { $response = $thread->{pt_execute}->PT_RETVAL();
PT_EXIT("$owx_dev has returned invalid data"); unless (length($response) == 10) {
}
unless (length($response->{readdata}) == 10) {
PT_EXIT("$owx_dev has returned invalid data") PT_EXIT("$owx_dev has returned invalid data")
}; };
$ret = OWXSWITCH_BinValues($hash,"ds2408.getstate",1,1,$owx_dev,$response->{writedata},10,$response->{readdata}); $ret = OWXSWITCH_BinValues($hash,"ds2408.getstate",1,1,$owx_dev,$thread->{'select'},10,$response);
if (defined $ret) { if (defined $ret) {
PT_EXIT($ret); PT_EXIT($ret);
} }
@ -1312,19 +1345,17 @@ sub OWXSWITCH_PT_GetState($) {
#-- issue the match ROM command \x55 and the read gpio command #-- issue the match ROM command \x55 and the read gpio command
# \xF5 plus 2 empty bytes # \xF5 plus 2 empty bytes
#-- reading 9 + 1 + 2 data bytes = 12 bytes #-- reading 9 + 1 + 2 data bytes = 12 bytes
$select = "\xF5"; $thread->{'select'}="\xF5";
unless (OWX_ASYNC_Execute( $master, $thread, 1, $owx_dev, $select, 2)) { $thread->{pt_execute} = OWX_ASYNC_PT_Execute($master,1,$owx_dev,$thread->{'select'},2);
PT_EXIT("device $owx_dev not accessible in reading"); $thread->{TimeoutTime} = gettimeofday()+2; #TODO: implement attribute-based timeout
} PT_WAIT_THREAD($thread->{pt_execute});
PT_WAIT_UNTIL($thread->{ExecuteResponse}); delete $thread->{TimeoutTime};
$response = $thread->{ExecuteResponse}; die $thread->{pt_execute}->PT_CAUSE() if ($thread->{pt_execute}->PT_STATE() == PT_ERROR);
unless ($response->{success}) { $response = $thread->{pt_execute}->PT_RETVAL();
unless (length($response) == 2) {
PT_EXIT("$owx_dev has returned invalid data"); PT_EXIT("$owx_dev has returned invalid data");
} }
unless (length($response->{readdata}) == 2) { $ret = OWXSWITCH_BinValues($hash,"ds2413.getstate",1,1,$owx_dev,$thread->{'select'},2,$response);
PT_EXIT("$owx_dev has returned invalid data");
}
$ret = OWXSWITCH_BinValues($hash,"ds2413.getstate",1,1,$owx_dev,$response->{writedata},2,$response->{readdata});
if (defined $ret) { if (defined $ret) {
PT_EXIT($ret); PT_EXIT($ret);
} }
@ -1332,6 +1363,7 @@ sub OWXSWITCH_PT_GetState($) {
PT_EXIT("unknown device family $hash->{OW_FAMILY}\n"); PT_EXIT("unknown device family $hash->{OW_FAMILY}\n");
} }
PT_END; PT_END;
});
} }
######################################################################################## ########################################################################################
@ -1345,8 +1377,11 @@ sub OWXSWITCH_PT_GetState($) {
sub OWXSWITCH_PT_SetState($$) { sub OWXSWITCH_PT_SetState($$) {
my ($thread,$hash,$value) = @_; my ($hash,$value) = @_;
return PT_THREAD( sub {
my ($thread) = @_;
my ($select,$res,@data); my ($select,$res,@data);
#-- ID of the device #-- ID of the device
@ -1366,14 +1401,12 @@ sub OWXSWITCH_PT_SetState($$) {
# \xAA at address TA1 = \x07 TA2 = \x00 # \xAA at address TA1 = \x07 TA2 = \x00
#-- reading 9 + 3 + 1 data bytes + 2 CRC bytes = 15 bytes #-- reading 9 + 3 + 1 data bytes + 2 CRC bytes = 15 bytes
unless (OWX_ASYNC_Execute( $master, $thread, 1, $owx_dev, "\xAA\x07\x00", 3)) { $thread->{pt_execute} = OWX_ASYNC_PT_Execute($master,1,$owx_dev,"\xAA\x07\x00", 3);
PT_EXIT("device $owx_dev not accessible in writing"); $thread->{TimeoutTime} = gettimeofday()+2; #TODO: implement attribute-based timeout
} PT_WAIT_THREAD($thread->{pt_execute});
PT_WAIT_UNTIL($thread->{ExecuteResponse}); delete $thread->{TimeoutTime};
unless ($thread->{ExecuteResponse}->{success}) { die $thread->{pt_execute}->PT_CAUSE() if ($thread->{pt_execute}->PT_STATE() == PT_ERROR);
PT_EXIT("state could not be set for device $owx_dev"); $res = $thread->{pt_execute}->PT_RETVAL();
}
$res = $thread->{ExecuteResponse}->{readdata};
#-- first step #-- first step
my $stat = ord(substr($res,0,1)); my $stat = ord(substr($res,0,1));
@ -1382,17 +1415,16 @@ sub OWXSWITCH_PT_SetState($$) {
#-- issue the match ROM command \x55 and the write status command #-- issue the match ROM command \x55 and the write status command
# \x55 at address TA1 = \x07 TA2 = \x00 # \x55 at address TA1 = \x07 TA2 = \x00
#-- reading 9 + 4 + 2 data bytes = 15 bytes #-- reading 9 + 4 + 2 data bytes = 15 bytes
$select=sprintf("\x55\x07\x00%c",$statneu); $thread->{'select'}=sprintf("\x55\x07\x00%c",$statneu);
unless (OWX_ASYNC_Execute( $master, $thread, 1, $owx_dev, $select, 2)) { $thread->{pt_execute} = OWX_ASYNC_PT_Execute($master,1,$owx_dev,$thread->{'select'}, 2);
PT_EXIT("device $owx_dev not accessible in writing"); $thread->{TimeoutTime} = gettimeofday()+2; #TODO: implement attribute-based timeout
} PT_WAIT_THREAD($thread->{pt_execute});
PT_WAIT_UNTIL($thread->{ExecuteResponse}); delete $thread->{TimeoutTime};
unless ($thread->{ExecuteResponse}->{success}) { die $thread->{pt_execute}->PT_CAUSE() if ($thread->{pt_execute}->PT_STATE() == PT_ERROR);
PT_EXIT("state could not be set for device $owx_dev"); $res = $thread->{pt_execute}->PT_RETVAL();
}
$res = $thread->{ExecuteResponse}->{readdata}; my $command = $thread->{'select'};
my $command = $thread->{ExecuteResponse}->{writedata};
#-- second step from above #-- second step from above
@data=split(//,$res); @data=split(//,$res);
@ -1416,14 +1448,12 @@ sub OWXSWITCH_PT_SetState($$) {
# \x5A plus the value byte and its complement # \x5A plus the value byte and its complement
$select=sprintf("\x5A%c%c",$value,255-$value); $select=sprintf("\x5A%c%c",$value,255-$value);
unless (OWX_ASYNC_Execute( $master, $thread, 1, $owx_dev, $select, 1)) { $thread->{pt_execute} = OWX_ASYNC_PT_Execute($master,1,$owx_dev,$select, 1);
PT_EXIT("device $owx_dev not accessible in writing"); $thread->{TimeoutTime} = gettimeofday()+2; #TODO: implement attribute-based timeout
} PT_WAIT_THREAD($thread->{pt_execute});
PT_WAIT_UNTIL($thread->{ExecuteResponse}); delete $thread->{TimeoutTime};
unless ($thread->{ExecuteResponse}->{success}) { die $thread->{pt_execute}->PT_CAUSE() if ($thread->{pt_execute}->PT_STATE() == PT_ERROR);
PT_EXIT("state could not be set for device $owx_dev"); $res = $thread->{pt_execute}->PT_RETVAL();
}
$res = $thread->{ExecuteResponse}->{readdata};
@data=split(//,$res); @data=split(//,$res);
if (@data != 1) { if (@data != 1) {
@ -1439,14 +1469,12 @@ sub OWXSWITCH_PT_SetState($$) {
#-- issue the match ROM command \x55 and the write gpio command #-- issue the match ROM command \x55 and the write gpio command
# \x5A plus the value byte and its complement # \x5A plus the value byte and its complement
$select=sprintf("\x5A%c%c",252+$value,3-$value); $select=sprintf("\x5A%c%c",252+$value,3-$value);
unless (OWX_ASYNC_Execute( $master, $thread, 1, $owx_dev, $select, 1)) { $thread->{pt_execute} = OWX_ASYNC_PT_Execute($master,1,$owx_dev,$select, 1);
PT_EXIT("device $owx_dev not accessible in writing"); $thread->{TimeoutTime} = gettimeofday()+2; #TODO: implement attribute-based timeout
} PT_WAIT_THREAD($thread->{pt_execute});
PT_WAIT_UNTIL($thread->{ExecuteResponse}); delete $thread->{TimeoutTime};
unless ($thread->{ExecuteResponse}->{success}) { die $thread->{pt_execute}->PT_CAUSE() if ($thread->{pt_execute}->PT_STATE() == PT_ERROR);
PT_EXIT("state could not be set for device $owx_dev"); $res = $thread->{pt_execute}->PT_RETVAL();
}
$res = $thread->{ExecuteResponse}->{readdata};
@data=split(//,$res); @data=split(//,$res);
if (@data != 1) { if (@data != 1) {
@ -1459,18 +1487,22 @@ sub OWXSWITCH_PT_SetState($$) {
PT_EXIT("unknown device family $hash->{OW_FAMILY}\n"); PT_EXIT("unknown device family $hash->{OW_FAMILY}\n");
} }
PT_END; PT_END;
});
} }
sub OWXSWITCH_PT_SetOutput($$$) { sub OWXSWITCH_PT_SetOutput($$$) {
my ($thread,$hash,$fnd,$nval) = @_; my ($hash,$fnd,$nval) = @_;
return PT_THREAD(sub {
my ($thread) = @_;
my ($ret,$value); my ($ret,$value);
PT_BEGIN($thread); PT_BEGIN($thread);
$thread->{task} = PT_THREAD(\&OWXSWITCH_PT_GetState); $thread->{task} = OWXSWITCH_PT_GetState($hash);
PT_WAIT_THREAD($thread->{task},$hash); PT_WAIT_THREAD($thread->{task});
$ret = $thread->{task}->PT_RETVAL(); $ret = $thread->{task}->PT_RETVAL();
if ($ret) { if ($ret) {
PT_EXIT($ret); PT_EXIT($ret);
@ -1484,13 +1516,14 @@ sub OWXSWITCH_PT_SetOutput($$$) {
if( $i == $fnd ); if( $i == $fnd );
} }
$thread->{value} = $value; $thread->{value} = $value;
$thread->{task} = PT_THREAD(\&OWXSWITCH_PT_SetState); $thread->{task} = OWXSWITCH_PT_SetState($hash,$thread->{value});
PT_WAIT_THREAD($thread->{task},$hash,$thread->{value}); PT_WAIT_THREAD($thread->{task});
$ret = $thread->{task}->PT_RETVAL(); $ret = $thread->{task}->PT_RETVAL();
if ($ret) { if ($ret) {
PT_EXIT($ret); PT_EXIT($ret);
} }
PT_END; PT_END;
});
} }
1; 1;

150
fhem/FHEM/21_OWTHERM.pm Executable file → Normal file
View File

@ -70,7 +70,7 @@ package main;
use vars qw{%attr %defs %modules $readingFnAttributes $init_done}; use vars qw{%attr %defs %modules $readingFnAttributes $init_done};
use strict; use strict;
use warnings; use warnings;
use Time::HiRes qw( gettimeofday tv_interval usleep ); use Time::HiRes qw( gettimeofday );
#add FHEM/lib to @INC if it's not allready included. Should rather be in fhem.pl than here though... #add FHEM/lib to @INC if it's not allready included. Should rather be in fhem.pl than here though...
BEGIN { BEGIN {
@ -86,7 +86,7 @@ no warnings 'deprecated';
sub Log3($$$); sub Log3($$$);
sub AttrVal($$$); sub AttrVal($$$);
my $owx_version="5.20"; my $owx_version="5.21";
my %gets = ( my %gets = (
"id" => "", "id" => "",
@ -138,6 +138,8 @@ sub OWTHERM_Initialize ($) {
$hash->{UndefFn} = "OWTHERM_Undef"; $hash->{UndefFn} = "OWTHERM_Undef";
$hash->{GetFn} = "OWTHERM_Get"; $hash->{GetFn} = "OWTHERM_Get";
$hash->{SetFn} = "OWTHERM_Set"; $hash->{SetFn} = "OWTHERM_Set";
$hash->{NotifyFn}= "OWTHERM_Notify";
$hash->{InitFn} = "OWTHERM_Init";
$hash->{AttrFn} = "OWTHERM_Attr"; $hash->{AttrFn} = "OWTHERM_Attr";
$hash->{AttrList}= "IODev model:DS1820,DS18B20,DS1822 loglevel:0,1,2,3,4,5 ". $hash->{AttrList}= "IODev model:DS1820,DS18B20,DS1822 loglevel:0,1,2,3,4,5 ".
"stateAL stateAH ". "stateAL stateAH ".
@ -254,9 +256,29 @@ sub OWTHERM_Define ($$) {
readingsSingleUpdate($hash,"state","defined",1); readingsSingleUpdate($hash,"state","defined",1);
Log3 $name, 3, "OWTHERM: Device $name defined."; Log3 $name, 3, "OWTHERM: Device $name defined.";
#-- Start timer for updates $hash->{NOTIFYDEV} = "global";
InternalTimer(time()+10, "OWTHERM_GetValues", $hash, 0);
if ($init_done) {
OWTHERM_Init($hash);
}
return undef;
}
sub OWTHERM_Notify ($$) {
my ($hash,$dev) = @_;
if( grep(m/^(INITIALIZED|REREADCFG)$/, @{$dev->{CHANGED}}) ) {
OWTHERM_Init($hash);
} elsif( grep(m/^SAVE$/, @{$dev->{CHANGED}}) ) {
}
}
sub OWTHERM_Init ($) {
my ($hash)=@_;
#-- Start timer for updates
RemoveInternalTimer($hash);
InternalTimer(gettimeofday()+10, "OWTHERM_GetValues", $hash, 0);
#--
readingsSingleUpdate($hash,"state","Initialized",1);
return undef; return undef;
} }
@ -307,6 +329,9 @@ sub OWTHERM_Attr(@) {
AssignIoPort($hash,$value); AssignIoPort($hash,$value);
if( defined($hash->{IODev}) ) { if( defined($hash->{IODev}) ) {
$hash->{ASYNC} = $hash->{IODev}->{TYPE} eq "OWX_ASYNC" ? 1 : 0; $hash->{ASYNC} = $hash->{IODev}->{TYPE} eq "OWX_ASYNC" ? 1 : 0;
if ($init_done) {
OWTHERM_Init($hash);
}
} }
last; last;
}; };
@ -425,6 +450,8 @@ sub OWTHERM_Get($@) {
return "$name.id => $value"; return "$name.id => $value";
} }
#-- hash of the busmaster
my $master = $hash->{IODev};
#-- Get other values according to interface type #-- Get other values according to interface type
my $interface= $hash->{IODev}->{TYPE}; my $interface= $hash->{IODev}->{TYPE};
@ -432,11 +459,17 @@ sub OWTHERM_Get($@) {
if($a[1] eq "present" ) { if($a[1] eq "present" ) {
#-- OWX interface #-- OWX interface
if( $interface =~ /^OWX/ ){ if( $interface =~ /^OWX/ ){
#-- hash of the busmaster
my $master = $hash->{IODev};
#-- asynchronous mode #-- asynchronous mode
if( $hash->{ASYNC} ){ if( $hash->{ASYNC} ){
$value = OWX_ASYNC_Verify($master,$hash->{ROM_ID}); my ($task,$task_state);
eval {
$task = OWX_ASYNC_PT_Verify($hash);
OWX_ASYNC_Schedule($hash,$task);
$task_state = OWX_ASYNC_RunToCompletion($master,$task);
};
return GP_Catch($@) if $@;
return $task->PT_CAUSE() if ($task_state == PT_ERROR or $task_state == PT_CANCELED);
return "$name.present => ".ReadingsVal($name,"present","unknown");
} else { } else {
$value = OWX_Verify($master,$hash->{ROM_ID}); $value = OWX_Verify($master,$hash->{ROM_ID});
} }
@ -463,12 +496,13 @@ sub OWTHERM_Get($@) {
#-- not different from getting all values .. #-- not different from getting all values ..
$ret = OWXTHERM_GetValues($hash); $ret = OWXTHERM_GetValues($hash);
}elsif( $interface eq "OWX_ASYNC" ){ }elsif( $interface eq "OWX_ASYNC" ){
#TODO use OWX_ASYNC_Schedule instead my ($task,$task_state);
my $task = PT_THREAD(\&OWXTHERM_PT_GetValues);
eval { eval {
while ($task->PT_SCHEDULE($hash)) { OWX_ASYNC_Poll($hash->{IODev}); }; $task = OWXTHERM_PT_GetValues($hash);
OWX_ASYNC_Schedule($hash,$task);
$task_state = OWX_ASYNC_RunToCompletion($master,$task);
}; };
$ret = ($@) ? GP_Catch($@) : $task->PT_RETVAL(); $ret = ($@) ? GP_Catch($@) : ($task_state == PT_ERROR or $task_state == PT_CANCELED) ? $task->PT_CAUSE() : $task->PT_RETVAL();
#-- OWFS interface #-- OWFS interface
}elsif( $interface eq "OWServer" ){ }elsif( $interface eq "OWServer" ){
$ret = OWFSTHERM_GetValues($hash); $ret = OWFSTHERM_GetValues($hash);
@ -531,7 +565,7 @@ sub OWTHERM_GetValues($@) {
#-- skip, if the conversion is driven by master #-- skip, if the conversion is driven by master
unless ( defined($attr{$name}{tempConv}) && ( $attr{$name}{tempConv} eq "onkick") ){ unless ( defined($attr{$name}{tempConv}) && ( $attr{$name}{tempConv} eq "onkick") ){
eval { eval {
OWX_ASYNC_Schedule( $hash, PT_THREAD(\&OWXTHERM_PT_GetValues),$hash ); OWX_ASYNC_Schedule( $hash, OWXTHERM_PT_GetValues($hash) );
}; };
$ret = GP_Catch($@) if $@; $ret = GP_Catch($@) if $@;
} }
@ -566,7 +600,8 @@ sub OWTHERM_InitializeDevice($) {
my ($hash) = @_; my ($hash) = @_;
my $name = $hash->{NAME}; my $name = $hash->{NAME};
my $interface = $hash->{IODev}->{TYPE}; my $master = $hash->{IODev};
my $interface = $master->{TYPE};
my @a = ($name,"",0); my @a = ($name,"",0);
my ($unit,$offset,$factor,$abbr,$value,$ret); my ($unit,$offset,$factor,$abbr,$value,$ret);
@ -633,12 +668,13 @@ sub OWTHERM_InitializeDevice($) {
if( $interface eq "OWX" ){ if( $interface eq "OWX" ){
$ret = OWXTHERM_SetValues($hash,$args); $ret = OWXTHERM_SetValues($hash,$args);
}elsif( $interface eq "OWX_ASYNC" ){ }elsif( $interface eq "OWX_ASYNC" ){
#TODO use OWX_ASYNC_Schedule instead my ($task,$task_state);
my $task = PT_THREAD(\&OWXTHERM_PT_SetValues);
eval { eval {
while ($task->PT_SCHEDULE($hash,$args)) { OWX_ASYNC_Poll($hash->{IODev}); }; $task = OWXTHERM_PT_SetValues($hash,$args);
OWX_ASYNC_Schedule($hash,$task);
$task_state = OWX_ASYNC_RunToCompletion($master,$task);
}; };
$ret = ($@) ? GP_Catch($@) : $task->PT_RETVAL(); $ret = ($@) ? GP_Catch($@) : ($task_state == PT_ERROR or $task_state == PT_CANCELED) ? $task->PT_CAUSE() : $task->PT_RETVAL();
#-- OWFS interface #-- OWFS interface
}elsif( $interface eq "OWServer" ){ }elsif( $interface eq "OWServer" ){
$ret = OWFSTHERM_SetValues($hash,$args); $ret = OWFSTHERM_SetValues($hash,$args);
@ -732,7 +768,7 @@ sub OWTHERM_Set($@) {
}elsif( $interface eq "OWX_ASYNC" ){ }elsif( $interface eq "OWX_ASYNC" ){
$args->{format} = 1; $args->{format} = 1;
eval { eval {
OWX_ASYNC_Schedule( $hash, PT_THREAD(\&OWXTHERM_PT_SetValues),$hash,$args ); OWX_ASYNC_Schedule( $hash, OWXTHERM_PT_SetValues($hash,$args) );
}; };
$ret = GP_Catch($@) if $@; $ret = GP_Catch($@) if $@;
#-- OWFS interface #-- OWFS interface
@ -876,11 +912,8 @@ sub OWFSTHERM_SetValues($$) {
# #
######################################################################################## ########################################################################################
sub OWXTHERM_BinValues($$$$$$$$) { sub OWXTHERM_BinValues($$$$$$) {
my ($hash, $context, $success, $reset, $owx_dev, $command, $numread, $res) = @_; my ($hash, $reset, $owx_dev, $command, $numread, $res) = @_;
#-- always check for success, unused are reset, numread
return unless ($success and ($context =~ /.*reading.*/));
#Log3 $name, 1,"OWXTHERM_BinValues context = $context"; #Log3 $name, 1,"OWXTHERM_BinValues context = $context";
@ -889,17 +922,15 @@ sub OWXTHERM_BinValues($$$$$$$$) {
#Log3 $name, 1,"OWXTHERM: data length from reading device is ".length($res)." bytes"; #Log3 $name, 1,"OWXTHERM: data length from reading device is ".length($res)." bytes";
#-- process results #-- process results
if( $res eq 0 ){ die "$owx_dev not accessible in 2nd step" unless ( defined $res and $res ne 0 );
return "$owx_dev not accessible in 2nd step";
}
#-- process results #-- process results
@data=split(//,$res); @data=split(//,$res);
return "invalid data length, ".int(@data)." instead of 9 bytes" die "invalid data length, ".int(@data)." instead of 9 bytes"
if (@data != 9); if (@data != 9);
return "invalid data" die "invalid data"
if (ord($data[7])<=0); if (ord($data[7])<=0);
return "invalid CRC" die "invalid CRC"
if (OWX_CRC8(substr($res,0,8),$data[8])==0); if (OWX_CRC8(substr($res,0,8),$data[8])==0);
#-- this must be different for the different device types #-- this must be different for the different device types
@ -948,7 +979,7 @@ sub OWXTHERM_BinValues($$$$$$$$) {
$ow_tln = ord($data[3]) > 127 ? 128-ord($data[3]) : ord($data[3]); $ow_tln = ord($data[3]) > 127 ? 128-ord($data[3]) : ord($data[3]);
} else { } else {
return "OWXTHERM: Unknown device family $hash->{OW_FAMILY}\n"; die "OWXTHERM: Unknown device family $hash->{OW_FAMILY}\n";
} }
#-- process alarm settings #-- process alarm settings
@ -984,9 +1015,6 @@ sub OWXTHERM_GetValues($) {
my $master = $hash->{IODev}; my $master = $hash->{IODev};
my $name = $hash->{NAME}; my $name = $hash->{NAME};
#-- reset presence
$hash->{PRESENT} = 0;
#-- check, if the conversion has been called before for all sensors #-- check, if the conversion has been called before for all sensors
if( defined($attr{$name}{tempConv}) && ( $attr{$name}{tempConv} eq "onkick") ){ if( defined($attr{$name}{tempConv}) && ( $attr{$name}{tempConv} eq "onkick") ){
$con=0; $con=0;
@ -1011,7 +1039,10 @@ sub OWXTHERM_GetValues($) {
if( $res eq 0 ); if( $res eq 0 );
return "$owx_dev has returned invalid data" return "$owx_dev has returned invalid data"
if( length($res)!=19); if( length($res)!=19);
return OWXTHERM_BinValues($hash,"ds182x.reading",1,undef,$owx_dev,undef,undef,substr($res,10,9)); eval {
OWXTHERM_BinValues($hash,undef,$owx_dev,undef,undef,substr($res,10,9));
};
return $@;
} }
####################################################################################### #######################################################################################
@ -1079,8 +1110,10 @@ sub OWXTHERM_SetValues($$) {
sub OWXTHERM_PT_GetValues($@) { sub OWXTHERM_PT_GetValues($@) {
my ($thread,$hash) = @_; my ($hash) = @_;
return PT_THREAD(sub {
my ($thread) = @_;
#-- For default, perform the conversion now #-- For default, perform the conversion now
my $con=1; my $con=1;
@ -1093,9 +1126,6 @@ sub OWXTHERM_PT_GetValues($@) {
PT_BEGIN($thread); PT_BEGIN($thread);
#-- reset presence
$hash->{PRESENT} = 0;
#-- check, if the conversion has been called before for all sensors #-- check, if the conversion has been called before for all sensors
if( defined($attr{$name}{tempConv}) && ( $attr{$name}{tempConv} eq "onkick") ){ if( defined($attr{$name}{tempConv}) && ( $attr{$name}{tempConv} eq "onkick") ){
$con=0; $con=0;
@ -1104,30 +1134,28 @@ sub OWXTHERM_PT_GetValues($@) {
#-- if the conversion has not been called before #-- if the conversion has not been called before
if( $con==1 ){ if( $con==1 ){
#-- issue the match ROM command \x55 and the start conversion command \x44 #-- issue the match ROM command \x55 and the start conversion command \x44
unless (OWX_ASYNC_Execute($master,$thread,1,$owx_dev,"\x44",0)) {
PT_EXIT("$owx_dev not accessible for convert");
}
my $now = gettimeofday(); my $now = gettimeofday();
my $delay = $convtimes{AttrVal($name,"resolution",12)}; my $delay = $convtimes{AttrVal($name,"resolution",12)};
$thread->{ExecuteTime} = $now + $delay*0.001; $thread->{ExecuteTime} = $now + $delay*0.001;
PT_YIELD_UNTIL(defined $thread->{ExecuteResponse} and (gettimeofday() >= $thread->{ExecuteTime})); $thread->{pt_execute} = OWX_ASYNC_PT_Execute($master,1,$owx_dev,"\x44",0);
$thread->{TimeoutTime} = gettimeofday()+2; #TODO: implement attribute-based timeout
PT_WAIT_THREAD($thread->{pt_execute});
delete $thread->{TimeoutTime};
die $thread->{pt_execute}->PT_CAUSE() if ($thread->{pt_execute}->PT_STATE() == PT_ERROR);
PT_YIELD_UNTIL(gettimeofday() >= $thread->{ExecuteTime});
delete $thread->{ExecuteTime};
} }
#-- NOW ask the specific device #-- NOW ask the specific device
#-- issue the match ROM command \x55 and the read scratchpad command \xBE #-- issue the match ROM command \x55 and the read scratchpad command \xBE
#-- reading 9 + 1 + 8 data bytes and 1 CRC byte = 19 bytes #-- reading 9 + 1 + 8 data bytes and 1 CRC byte = 19 bytes
unless (OWX_ASYNC_Execute($master,$thread,1,$owx_dev,"\xBE",9)) { $thread->{pt_execute} = OWX_ASYNC_PT_Execute($master,1,$owx_dev,"\xBE",9);
PT_EXIT("$owx_dev not accessible in reading"); $thread->{TimeoutTime} = gettimeofday()+2; #TODO: implement attribute-based timeout
} PT_WAIT_THREAD($thread->{pt_execute});
PT_WAIT_UNTIL(defined $thread->{ExecuteResponse}); delete $thread->{TimeoutTime};
my $response = $thread->{ExecuteResponse}; die $thread->{pt_execute}->PT_CAUSE() if ($thread->{pt_execute}->PT_STATE() == PT_ERROR);
unless ($response->{success}) { OWXTHERM_BinValues($hash,1,$owx_dev,undef,9,$thread->{pt_execute}->PT_RETVAL());
PT_EXIT("$owx_dev read not successful");
}
my $res = OWXTHERM_BinValues($hash,"ds182x.reading",1,1,$owx_dev,undef,$response->{numread},$response->{readdata});
if ($res) {
PT_EXIT($res);
}
PT_END; PT_END;
});
} }
####################################################################################### #######################################################################################
@ -1140,7 +1168,11 @@ sub OWXTHERM_PT_GetValues($@) {
######################################################################################## ########################################################################################
sub OWXTHERM_PT_SetValues($$) { sub OWXTHERM_PT_SetValues($$) {
my ($thread, $hash, $args) = @_;
my ($hash,$args) = @_;
return PT_THREAD( sub {
my ($thread) = @_;
my ($i,$j,$k); my ($i,$j,$k);
@ -1180,10 +1212,9 @@ sub OWXTHERM_PT_SetValues($$) {
# 3. \x48 sent by WriteBytePower after match ROM => command ok, no effect on EEPROM # 3. \x48 sent by WriteBytePower after match ROM => command ok, no effect on EEPROM
my $select=sprintf("\x4E%c%c%c",$thp,$tlp,$cfg); my $select=sprintf("\x4E%c%c%c",$thp,$tlp,$cfg);
unless (OWX_ASYNC_Execute($master,$thread,1,$owx_dev,$select,3)) { $thread->{pt_execute} = OWX_ASYNC_PT_Execute($master,1,$owx_dev,$select,3);
PT_EXIT("OWXTHERM: Device $owx_dev not accessible"); PT_WAIT_THREAD($thread->{pt_execute});
} die $thread->{pt_execute}->PT_CAUSE() if ($thread->{pt_execute}->PT_STATE() == PT_ERROR);
PT_WAIT_UNTIL(defined $thread->{ExecuteResponse});
#-- process results #-- process results
$hash->{PRESENT} = 1; $hash->{PRESENT} = 1;
@ -1191,6 +1222,7 @@ sub OWXTHERM_PT_SetValues($$) {
OWTHERM_FormatValues($hash); OWTHERM_FormatValues($hash);
} }
PT_END; PT_END;
});
} }
1; 1;

View File

@ -32,14 +32,14 @@ sub GP_Catch($) {
return undef; return undef;
} }
sub GP_ForallClients($$$) sub GP_ForallClients($$@)
{ {
my ($hash,$fn,$args) = @_; my ($hash,$fn,@args) = @_;
foreach my $d ( sort keys %main::defs ) { foreach my $d ( sort keys %main::defs ) {
if ( defined( $main::defs{$d} ) if ( defined( $main::defs{$d} )
&& defined( $main::defs{$d}{IODev} ) && defined( $main::defs{$d}{IODev} )
&& $main::defs{$d}{IODev} == $hash ) { && $main::defs{$d}{IODev} == $hash ) {
&$fn($main::defs{$d},$args); &$fn($main::defs{$d},@args);
} }
} }
return undef; return undef;

View File

@ -1,186 +0,0 @@
##############################################
# $Id$
##############################################
package OWX_Executor;
use strict;
use warnings;
use constant {
DISCOVER => 1,
ALARMS => 2,
VERIFY => 3,
EXECUTE => 4,
EXIT => 5,
LOG => 6
};
sub new() {
my $class = shift;
my $self = {};
$self->{worker} = OWX_Worker->new($self);
return bless $self,$class;
};
sub discover($) {
my ($self,$hash) = @_;
if($self->{worker}->submit( { command => DISCOVER }, $hash )) {
$self->poll($hash);
return 1;
}
return undef;
}
sub alarms($) {
my ($self,$hash) = @_;
if($self->{worker}->submit( { command => ALARMS }, $hash )) {
$self->poll($hash);
return 1;
}
return undef;
}
sub verify($$) {
my ($self,$hash,$device) = @_;
if($self->{worker}->submit( { command => VERIFY, address => $device }, $hash )) {
$self->poll($hash);
return 1;
}
return undef;
}
sub execute($$$$$$$) {
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
}, $hash )) {
$self->poll($hash);
return 1;
}
return undef;
};
sub exit($) {
my ( $self,$hash ) = @_;
if($self->{worker}->submit( { command => EXIT }, $hash )) {
$self->poll($hash);
return 1;
}
return undef;
}
sub poll($) {
my ( $self,$hash ) = @_;
$self->read();
$self->{worker}->PT_SCHEDULE($hash);
}
# start of worker code
package OWX_Worker;
use Time::HiRes qw( gettimeofday tv_interval usleep );
use ProtoThreads;
no warnings 'deprecated';
use vars qw/@ISA/;
@ISA='ProtoThreads';
sub new($) {
my ($class,$owx) = @_;
my $worker = PT_THREAD(\&pt_main);
$worker->{commands} = [];
$worker->{delayed} = {};
$worker->{owx} = $owx;
return bless $worker,$class;
}
sub submit($$) {
my ($self,$command,$hash) = @_;
push @{$self->{commands}}, $command;
$self->PT_SCHEDULE($hash);
return 1;
}
sub pt_main($) {
my ( $self, $hash ) = @_;
my $item = $self->{item};
PT_BEGIN($self);
PT_WAIT_UNTIL($item = $self->nextItem($hash));
$self->{item} = $item;
REQUEST_HANDLER: {
my $command = $item->{command};
$command eq OWX_Executor::DISCOVER and do {
PT_WAIT_THREAD($self->{owx}->{pt_discover},$self->{owx});
my $devices = $self->{owx}->{pt_discover}->PT_RETVAL();
if (defined $devices) {
main::OWX_ASYNC_AfterSearch($hash,$devices);
}
PT_EXIT;
};
$command eq OWX_Executor::ALARMS and do {
PT_WAIT_THREAD($self->{owx}->{pt_alarms},$self->{owx});
my $devices = $self->{owx}->{pt_alarms}->PT_RETVAL();
if (defined $devices) {
main::OWX_ASYNC_AfterAlarms($hash,$devices);
}
PT_EXIT;
};
$command eq OWX_Executor::VERIFY and do {
PT_WAIT_THREAD($self->{owx}->{pt_verify},$self->{owx},$item->{address});
my $devices = $self->{owx}->{pt_verify}->PT_RETVAL();
if (defined $devices) {
main::OWX_ASYNC_AfterVerify($hash,$devices);
}
PT_EXIT;
};
$command eq OWX_Executor::EXECUTE and do {
PT_WAIT_THREAD($self->{owx}->{pt_execute},$self->{owx},$hash,$item->{context},$item->{reset},$item->{address},$item->{writedata},$item->{numread});
my $res = $self->{owx}->{pt_execute}->PT_RETVAL();
unless (defined $res) {
main::OWX_ASYNC_AfterExecute($hash,$item->{context},undef,$item->{reset},$item->{address},$item->{writedata},$item->{numread},undef);
PT_EXIT;
}
my $writelen = defined $item->{writedata} ? split (//,$item->{writedata}) : 0;
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);
PT_EXIT;
};
$command eq OWX_Executor::EXIT and do {
main::OWX_ASYNC_Disconnected($hash);
PT_EXIT;
};
main::Log3($hash->{NAME},3,"OWX_Executor: unexpected command: "+$command);
};
PT_END;
};
sub nextItem($) {
my ( $self,$hash ) = @_;
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";
} else {
main::Log3 $hash->{NAME},5,"OWX_Executor: command $item->{command} eligible to run";
}
}
return $item;
}
1;

View File

@ -36,7 +36,9 @@ BEGIN {
}; };
use Device::Firmata::Constants qw/ :all /; use Device::Firmata::Constants qw/ :all /;
use Time::HiRes qw(gettimeofday tv_interval); use Time::HiRes qw( gettimeofday );
use ProtoThreads;
no warnings 'deprecated';
sub new() { sub new() {
my ($class) = @_; my ($class) = @_;
@ -103,41 +105,27 @@ sub FRM_OWX_observer
my $command = $data->{command}; my $command = $data->{command};
COMMAND_HANDLER: { COMMAND_HANDLER: {
$command eq "READ_REPLY" and do { $command eq "READ_REPLY" and do {
my $id = $data->{id}; $self->{responses}->{$data->{id}} = $data->{data}; # // $data->{device} // "defaultid"}
my $request = ( defined $id ) ? $self->{requests}->{$id} : undef; main::Log3 ($self->{name},5,"FRM_OWX_observer: READ_REPLY $data->{id}: ".join " ",map sprintf("%02X",$_),@{$data->{data}}) if $self->{debug};
unless ( defined $request ) {
last unless ( defined $data->{device} );
my $owx_device = FRM_OWX_firmata_to_device( $data->{device} );
my %requests = %{ $self->{requests} };
foreach my $key ( keys %requests ) {
if ( $requests{$key}->{device} eq $owx_device ) {
$request = $requests{$key};
$id = $key;
last;
};
};
};
last unless ( defined $request );
my $owx_data = pack "C*", @{ $data->{data} };
my $owx_device = $request->{device};
my $context = $request->{context};
my $reqcommand = $request->{command};
my $writedata = pack "C*", @{ $reqcommand->{'write'} } if ( defined $reqcommand->{'write'} );
main::OWX_ASYNC_AfterExecute( $self->{hash}, $context, 1, $reqcommand->{'reset'}, $owx_device, $writedata, $reqcommand->{'read'}, $owx_data);
delete $self->{requests}->{$id};
last; last;
}; };
( $command eq "SEARCH_REPLY" or $command eq "SEARCH_ALARMS_REPLY" ) and do { ( $command eq "SEARCH_REPLY" or $command eq "SEARCH_ALARMS_REPLY" ) and do {
my @owx_devices = (); my @owx_devices = ();
foreach my $device ( @{ $data->{devices} } ) { foreach my $device ( @{ $data->{devices} } ) {
push @owx_devices, FRM_OWX_firmata_to_device($device); push @owx_devices, firmata_to_device($device);
}; };
if ( $command eq "SEARCH_REPLY" ) { if ( $command eq "SEARCH_REPLY" ) {
$self->{devs} = \@owx_devices; $self->{devs} = \@owx_devices;
main::OWX_ASYNC_AfterSearch( $self->{hash}, \@owx_devices ); main::Log3 ($self->{name},5,"FRM_OWX_observer: SEARCH_REPLY: ".join ",",@owx_devices) if $self->{debug};
$self->{devs_timestamp} = gettimeofday();
#TODO avoid OWX_ASYNC_AfterSearch to be called twice
main::OWX_ASYNC_AfterSearch($self->{hash},\@owx_devices);
} else { } else {
$self->{alarmdevs} = \@owx_devices; $self->{alarmdevs} = \@owx_devices;
main::OWX_ASYNC_AfterAlarms( $self->{hash}, \@owx_devices ); main::Log3 ($self->{name},5,"FRM_OWX_observer: SEARCH_ALARMS_REPLY: ".join ",",@owx_devices) if $self->{debug};
$self->{alarmdevs_timestamp} = gettimeofday();
#TODO avoid OWX_ASYNC_AfterAlarms to be called twice
main::OWX_ASYNC_AfterAlarms($self->{hash},\@owx_devices);
}; };
last; last;
}; };
@ -147,7 +135,7 @@ COMMAND_HANDLER: {
########### functions implementing interface to OWX ########## ########### functions implementing interface to OWX ##########
sub FRM_OWX_device_to_firmata sub device_to_firmata
{ {
my @device; my @device;
foreach my $hbyte ( unpack "A2xA2A2A2A2A2A2xA2", shift ) { foreach my $hbyte ( unpack "A2xA2A2A2A2A2A2xA2", shift ) {
@ -160,7 +148,7 @@ sub FRM_OWX_device_to_firmata
} }
} }
sub FRM_OWX_firmata_to_device sub firmata_to_device
{ {
my $device = shift; my $device = shift;
return sprintf( "%02X.%02X%02X%02X%02X%02X%02X.%02X", $device->{family}, @{ $device->{identity} }, $device->{crc} ); return sprintf( "%02X.%02X%02X%02X%02X%02X%02X.%02X", $device->{family}, @{ $device->{identity} }, $device->{crc} );
@ -168,82 +156,114 @@ sub FRM_OWX_firmata_to_device
######################################################################################## ########################################################################################
# #
# asynchronous methods search, alarms and execute # factory methods for protothreads running discover, search, alarms and execute
# #
######################################################################################## ########################################################################################
sub discover($) { ########################################################################################
my ( $self, $hash ) = @_; #
my $success = undef; # Discover - Find devices on the 1-Wire bus
eval { #
if ( my $firmata = main::FRM_Client_FirmataDevice($hash) and my $pin = $self->{pin} ) { # Parameter hash = hash of bus master
$firmata->onewire_search($pin); #
$success = 1; # Return 1, if alarmed devices found, 0 otherwise.
}; #
}; ########################################################################################
if ($@) {
main::Log( 5, $@ );
$self->exit($hash);
};
return $success;
};
sub alarms($) { sub get_pt_discover() {
my ( $self, $hash ) = @_; my ($self) = @_;
my $success = undef; return PT_THREAD(sub {
eval { my ($thread) = @_;
if ( my $firmata = main::FRM_Client_FirmataDevice($hash) and my $pin = $self->{pin} ) { PT_BEGIN($thread);
$firmata->onewire_search_alarms($pin); delete $self->{devs};
$success = 1; main::FRM_Client_FirmataDevice($self->{hash})->onewire_search($self->{pin});
}; PT_WAIT_UNTIL(defined $self->{devs});
}; PT_EXIT($self->{devs});
if ($@) { PT_END;
$self->exit($hash); });
}; }
return $success;
};
sub execute($$$$$$) { ########################################################################################
my ( $self, $hash, $context, $reset, $owx_dev, $data, $numread ) = @_; #
# Alarms - Find devices on the 1-Wire bus, which have the alarm flag set
#
# Return number of alarmed devices
#
########################################################################################
my $success = undef; sub get_pt_alarms() {
my ($self) = @_;
return PT_THREAD(sub {
my ($thread) = @_;
PT_BEGIN($thread);
delete $self->{alarmdevs};
main::FRM_Client_FirmataDevice($self->{hash})->onewire_search_alarms($self->{pin});
PT_WAIT_UNTIL(defined $self->{alarmdevs});
PT_EXIT($self->{alarmdevs});
PT_END;
});
}
eval { sub get_pt_verify($) {
if ( my $firmata = main::FRM_Client_FirmataDevice($hash) and my $pin = $self->{pin} ) { my ($self,$dev) = @_;
my @data = unpack "C*", $data if defined $data; return PT_THREAD(sub {
my $id = $self->{id} if ($numread); my ($thread) = @_;
PT_BEGIN($thread);
delete $self->{devs};
main::FRM_Client_FirmataDevice($self->{hash})->onewire_search($self->{pin});
PT_WAIT_UNTIL(defined $self->{devs});
PT_EXIT(scalar(grep {$dev eq $_} @{$self->{devs}}));
PT_END;
});
}
########################################################################################
#
# Complex - Send match ROM, data block and receive bytes as response
#
# Parameter hash = hash of bus master,
# owx_dev = ROM ID of device
# data = string to send
# numread = number of bytes to receive
#
# Return response, if OK
# 0 if not OK
#
########################################################################################
sub get_pt_execute($$$$) {
my ($self, $reset, $owx_dev, $writedata, $numread) = @_;
return PT_THREAD(sub {
my ($thread) = @_;
PT_BEGIN($thread);
if ( my $firmata = main::FRM_Client_FirmataDevice($self->{hash}) and my $pin = $self->{pin} ) {
my @data = unpack "C*", $writedata if defined $writedata;
my $id = $self->{id};
my $ow_command = { my $ow_command = {
'reset' => $reset, 'reset' => $reset,
'skip' => defined($owx_dev) ? undef : 1, 'skip' => defined($owx_dev) ? undef : 1,
'select' => defined($owx_dev) ? FRM_OWX_device_to_firmata($owx_dev) : undef, 'select' => defined($owx_dev) ? device_to_firmata($owx_dev) : undef,
'read' => $numread, 'read' => $numread,
'write' => @data ? \@data : undef, 'write' => @data ? \@data : undef,
'delay' => undef, 'delay' => undef,
'id' => $numread ? $id : undef 'id' => $numread ? $id : undef
}; };
if ($numread) { main::Log3 ($self->{name},5,"FRM_OWX_Execute: $id: $owx_dev [".join(" ",(map sprintf("%02X",$_),@data))."] numread: ".(defined $numread ? $numread : 0)) if $self->{debug};
$owx_dev = '00.000000000000.00' unless defined $owx_dev;
$self->{requests}->{$id} = {
context => $context,
command => $ow_command,
device => $owx_dev
};
$self->{id} = ( ( $id + 1 ) & 0xFFFF );
};
$firmata->onewire_command_series( $pin, $ow_command ); $firmata->onewire_command_series( $pin, $ow_command );
$success = 1; if ($numread) {
$thread->{id} = $id;
$self->{id} = ( $id + 1 ) & 0xFFFF;
delete $self->{responses}->{$id};
PT_WAIT_UNTIL(defined $self->{responses}->{$thread->{id}});
my $ret = pack "C*", @{$self->{responses}->{$thread->{id}}};
delete $self->{responses}->{$thread->{id}};
PT_EXIT($ret);
}; };
}; };
if ($@) { PT_END;
main::Log3 $hash->{NAME},1,"OWX_FRM: $@"; });
#$self->exit($hash);
};
unless ($numread) {
main::OWX_ASYNC_AfterExecute( $hash, $context, $success, $reset, $owx_dev, $data, $numread, "" );
main::InternalTimer(gettimeofday(), "OWX_ASYNC_RunTasks", $hash,0);
}
return $success;
}; };
sub exit($) { sub exit($) {
@ -258,22 +278,4 @@ sub poll($) {
} }
}; };
#sub printqueues($$) {
# my ($self,$hash,$calledfrom) = @_;
# my $name = $hash->{NAME};
# main::Log3 $name,5,"OWX_ASYNC all queues, called from :".$calledfrom;
# my $delayed = $self->{delayed};
#
# foreach my $address ( keys %$delayed ) {
# my $msg = $address.": until: ";
# $msg .= $delayed->{$address}->{'until'} ? $delayed->{$address}->{'until'}->[0].",".$delayed->{$address}->{'until'}->[1] : "---";
# $msg .= " items: [";
# foreach my $item (@{$delayed->{$address}->{'items'}}) {
# $msg .= $item->{context}.",";
# }
# $msg .= "]";
# main::Log3 $name,5,$msg;
# }
#}
1; 1;

View File

@ -29,8 +29,8 @@ use strict;
use warnings; use warnings;
use vars qw/@ISA/; use vars qw/@ISA/;
@ISA='OWX_Executor';
use Time::HiRes qw( gettimeofday );
use ProtoThreads; use ProtoThreads;
no warnings 'deprecated'; no warnings 'deprecated';
@ -42,35 +42,31 @@ no warnings 'deprecated';
sub new() { sub new() {
my $class = shift; my $class = shift;
my $self = {
require "$main::attr{global}{modpath}/FHEM/OWX_Executor.pm"; interface => "serial",
my $self = OWX_Executor->new();
$self->{interface} = "serial";
#-- baud rate serial interface #-- baud rate serial interface
$self->{baud} = 9600; baud => 9600,
#-- 16 byte search string #-- 16 byte search string
$self->{search} = [0,0,0,0 ,0,0,0,0, 0,0,0,0, 0,0,0,0]; search => [0,0,0,0 ,0,0,0,0, 0,0,0,0, 0,0,0,0],
$self->{ROM_ID} = [0,0,0,0 ,0,0,0,0]; ROM_ID => [0,0,0,0 ,0,0,0,0],
#-- search state for 1-Wire bus search #-- search state for 1-Wire bus search
$self->{LastDiscrepancy} = 0; LastDiscrepancy => 0,
$self->{LastFamilyDiscrepancy} = 0; LastFamilyDiscrepancy => 0,
$self->{LastDeviceFlag} = 0; LastDeviceFlag => 0,
#-- module version #-- module version
$self->{version} = 4.1; version => 4.1,
$self->{alarmdevs} = []; alarmdevs => [],
$self->{devs} = []; devs => [],
$self->{pt_alarms} = PT_THREAD(\&pt_alarms); timeout => 1.0, #default timeout 1 sec.
$self->{pt_discover} = PT_THREAD(\&pt_discover); };
$self->{pt_verify} = PT_THREAD(\&pt_verify);
$self->{pt_execute} = PT_THREAD(\&pt_execute);
$self->{timeout} = 1.0; #default timeout 1 sec.
return bless $self,$class; return bless $self,$class;
} }
sub poll($) {
my ( $self ) = @_;
$self->read();
}
######################################################################################## ########################################################################################
# #
# Public methods # Public methods
@ -116,9 +112,10 @@ sub Define ($$) {
# #
######################################################################################## ########################################################################################
sub pt_alarms () { sub get_pt_alarms() {
my ($thread,$self) = @_; my ($self) = @_;
return PT_THREAD(sub {
my ($thread) = @_;
PT_BEGIN($thread); PT_BEGIN($thread);
$self->{alarmdevs} = []; $self->{alarmdevs} = [];
#-- Discover all alarmed devices on the 1-Wire bus #-- Discover all alarmed devices on the 1-Wire bus
@ -131,6 +128,7 @@ sub pt_alarms () {
main::Log3($self->{name},5, " Alarms = ".join(' ',@{$self->{alarmdevs}})); main::Log3($self->{name},5, " Alarms = ".join(' ',@{$self->{alarmdevs}}));
PT_EXIT($self->{alarmdevs}); PT_EXIT($self->{alarmdevs});
PT_END; PT_END;
});
} }
######################################################################################## ########################################################################################
@ -147,16 +145,20 @@ sub pt_alarms () {
# #
######################################################################################## ########################################################################################
sub pt_execute($$$$$$$) { sub get_pt_execute($$$$) {
my ($thread, $self, $hash, $context, $reset, $dev, $writedata, $numread) = @_; my ($self, $reset, $dev, $writedata, $numread) = @_;
return PT_THREAD(sub {
my ($thread) = @_;
PT_BEGIN($thread); PT_BEGIN($thread);
$thread->{writedata} = $writedata;
#-- get the interface #-- get the interface
my $interface = $self->{interface}; my $interface = $self->{interface};
my $hwdevice = $self->{hwdevice}; my $hwdevice = $self->{hwdevice};
unless (defined $hwdevice) {
PT_EXIT unless (defined $hwdevice); PT_EXIT;
}
$self->reset() if ($reset); $self->reset() if ($reset);
@ -203,7 +205,9 @@ sub pt_execute($$$$$$$) {
PT_WAIT_UNTIL($self->response_ready()); PT_WAIT_UNTIL($self->response_ready());
PT_EXIT if ($reset and !$self->reset_response()); if ($reset and !$self->reset_response()) {
PT_EXIT
}
my $res = $self->{string_in}; my $res = $self->{string_in};
#-- for debugging #-- for debugging
@ -211,8 +215,14 @@ sub pt_execute($$$$$$$) {
main::Log3($self->{name},5,"OWX_SER::Execute: Receiving ".unpack ("H*",$res)); main::Log3($self->{name},5,"OWX_SER::Execute: Receiving ".unpack ("H*",$res));
} }
PT_EXIT($res); if (defined $res) {
my $writelen = defined $thread->{writedata} ? split (//,$thread->{writedata}) : 0;
my @result = split (//, $res);
my $readdata = 9+$writelen < @result ? substr($res,9+$writelen) : "";
PT_EXIT($readdata);
}
PT_END; PT_END;
});
} }
######################################################################################## ########################################################################################
@ -225,8 +235,10 @@ sub pt_execute($$$$$$$) {
# #
######################################################################################## ########################################################################################
sub pt_discover($) { sub get_pt_discover() {
my ($thread,$self) = @_; my ($self) = @_;
return PT_THREAD(sub {
my ($thread) = @_;
PT_BEGIN($thread); PT_BEGIN($thread);
#-- Discover all alarmed devices on the 1-Wire bus #-- Discover all alarmed devices on the 1-Wire bus
$self->first("discover"); $self->first("discover");
@ -237,6 +249,7 @@ sub pt_discover($) {
} while( $self->{LastDeviceFlag}==0 ); } while( $self->{LastDeviceFlag}==0 );
PT_EXIT($self->{devs}); PT_EXIT($self->{devs});
PT_END; PT_END;
});
} }
######################################################################################## ########################################################################################
@ -382,8 +395,10 @@ sub Disconnect($) {
# #
######################################################################################## ########################################################################################
sub pt_verify ($) { sub get_pt_verify($) {
my ($thread,$self,$dev) = @_; my ($self,$dev) = @_;
return PT_THREAD(sub {
my ($thread) = @_;
my $i; my $i;
PT_BEGIN($thread); PT_BEGIN($thread);
#-- from search string to byte id #-- from search string to byte id
@ -410,10 +425,11 @@ sub pt_verify ($) {
if ($dev eq $dev2){ if ($dev eq $dev2){
PT_EXIT(1); PT_EXIT(1);
}else{ }else{
PT_EXIT; PT_EXIT(0);
} }
PT_END; PT_END;
} });
};
####################################################################################### #######################################################################################
# #

View File

@ -1,4 +1,4 @@
# Perl Protothreads Version 1.01 # Perl Protothreads Version 1.04
# #
# a lightwight pseudo-threading framework for perl that is # a lightwight pseudo-threading framework for perl that is
# heavily inspired by Adam Dunkels protothreads for the c-language # heavily inspired by Adam Dunkels protothreads for the c-language
@ -58,16 +58,19 @@
package ProtoThreads; package ProtoThreads;
use constant { use constant {
PT_WAITING => 0, PT_INITIAL => 0,
PT_EXITED => 1, PT_WAITING => 1,
PT_ENDED => 2, PT_YIELDED => 2,
PT_YIELDED => 3, PT_EXITED => 3,
PT_ENDED => 4,
PT_ERROR => 5,
PT_CANCELED => 6,
}; };
my $DEBUG=0; my $DEBUG=0;
use Exporter 'import'; use Exporter 'import';
@EXPORT = qw(PT_THREAD PT_WAITING PT_EXITED PT_ENDED PT_YIELDED PT_INIT PT_SCHEDULE); @EXPORT = qw(PT_THREAD PT_INITIAL PT_WAITING PT_YIELDED PT_EXITED PT_ENDED PT_ERROR PT_CANCELED PT_INIT PT_SCHEDULE);
@EXPORT_OK = qw(); @EXPORT_OK = qw();
use Text::Balanced qw ( use Text::Balanced qw (
@ -77,14 +80,17 @@ use Text::Balanced qw (
sub PT_THREAD($) { sub PT_THREAD($) {
my $method = shift; my $method = shift;
return bless({ return bless({
PT_THREAD_STATE => 0, PT_THREAD_STATE => PT_INITIAL,
PT_THREAD_POSITION => 0,
PT_THREAD_METHOD => $method PT_THREAD_METHOD => $method
}, "ProtoThreads"); }, "ProtoThreads");
} }
sub PT_INIT($) { sub PT_INIT($) {
my $self = shift; my $self = shift;
$self->{PT_THREAD_STATE} = 0; $self->{PT_THREAD_POSITION} = 0;
$self->{PT_THREAD_STATE} = PT_INITIAL;
delete $self->{PT_THREAD_ERROR};
} }
sub PT_SCHEDULE(@) { sub PT_SCHEDULE(@) {
@ -93,11 +99,28 @@ sub PT_SCHEDULE(@) {
return ($state == PT_WAITING or $state == PT_YIELDED); return ($state == PT_WAITING or $state == PT_YIELDED);
} }
sub PT_CANCEL($) {
my ($self,$cause) = @_;
$self->{PT_THREAD_POSITION} = 0;
$self->{PT_THREAD_ERROR} = $cause;
$self->{PT_THREAD_STATE} = PT_CANCELED;
}
sub PT_RETVAL() { sub PT_RETVAL() {
my $self = shift; my $self = shift;
return $self->{PT_THREAD_RETURN}; return $self->{PT_THREAD_RETURN};
} }
sub PT_STATE() {
my $self = shift;
return $self->{PT_THREAD_STATE};
}
sub PT_CAUSE() {
my $self = shift;
return $self->{PT_THREAD_ERROR};
}
sub PT_NEXTCOMMAND($$) { sub PT_NEXTCOMMAND($$) {
my ($code,$command) = @_; my ($code,$command) = @_;
if ($code =~ /$command\s*(?=\()/s) { if ($code =~ /$command\s*(?=\()/s) {
@ -121,66 +144,68 @@ FILTER_ONLY
my $code = $_; my $code = $_;
my $counter = 1; my $counter = 1;
my ($success,$before,$arg,$after); my ($success,$before,$arg,$after,$beforeblock);
while(1) { while(1) {
my $thread = " - no PT_BEGIN before use of thread - "; ($success,$beforeblock,$arg,$after) = PT_NEXTCOMMAND($code,"PT_BEGIN");
($success,$before,$arg,$after) = PT_NEXTCOMMAND($code,"PT_BEGIN");
if ($success) { if ($success) {
$thread = $arg; if ($after =~ /PT_END\s*;/s) {
$code=$before."my \$PT_THREAD_STATE = eval { my \$PT_YIELD_FLAG = 1; goto ".$thread."->{PT_THREAD_STATE} if ".$thread."->{PT_THREAD_STATE};".$after; my $thread = $arg;
my $block = $thread."->{PT_THREAD_STATE} = eval { my \$PT_YIELD_FLAG = 1; goto ".$thread."->{PT_THREAD_POSITION} if ".$thread."->{PT_THREAD_POSITION};".$`.$thread."->{PT_THREAD_POSITION} = 0; delete ".$thread."->{PT_THREAD_RETURN}; return PT_ENDED; }; if (\$\@) {".$thread."->{PT_THREAD_STATE} = PT_ERROR; ".$thread."->{PT_THREAD_ERROR} = \$\@; }; return ".$thread."->{PT_THREAD_STATE};";
my $afterblock = $';
while (1) { while (1) {
($success,$before,$arg,$after) = PT_NEXTCOMMAND($code,"PT_YIELD_UNTIL"); ($success,$before,$arg,$after) = PT_NEXTCOMMAND($block,"PT_YIELD_UNTIL");
if ($success) { if ($success) {
$code=$before."\$PT_YIELD_FLAG = 0; ".$thread."->{PT_THREAD_STATE} = 'PT_LABEL_$counter'; PT_LABEL_$counter: return PT_YIELDED unless (\$PT_YIELD_FLAG and ($arg));".$after; $block=$before."\$PT_YIELD_FLAG = 0; ".$thread."->{PT_THREAD_POSITION} = 'PT_LABEL_$counter'; PT_LABEL_$counter: return PT_YIELDED unless (\$PT_YIELD_FLAG and ($arg));".$after;
$counter++; $counter++;
next; next;
} }
if ($code =~ /PT_YIELD\s*;/s) { if ($block =~ /PT_YIELD\s*;/s) {
$code = $`."\$PT_YIELD_FLAG = 0; ".$thread."->{PT_THREAD_STATE} = 'PT_LABEL_$counter'; PT_LABEL_$counter: return PT_YIELDED unless \$PT_YIELD_FLAG;".$'; $block = $`."\$PT_YIELD_FLAG = 0; ".$thread."->{PT_THREAD_POSITION} = 'PT_LABEL_$counter'; PT_LABEL_$counter: return PT_YIELDED unless \$PT_YIELD_FLAG;".$';
$counter++; $counter++;
next; next;
} }
($success,$before,$arg,$after) = PT_NEXTCOMMAND($code,"PT_WAIT_UNTIL"); ($success,$before,$arg,$after) = PT_NEXTCOMMAND($block,"PT_WAIT_UNTIL");
if ($success) { if ($success) {
$code=$before.$thread."->{PT_THREAD_STATE} = 'PT_LABEL_$counter'; PT_LABEL_$counter: return PT_WAITING unless ($arg);".$after; $block=$before.$thread."->{PT_THREAD_POSITION} = 'PT_LABEL_$counter'; PT_LABEL_$counter: return PT_WAITING unless ($arg);".$after;
$counter++; $counter++;
next; next;
} }
($success,$before,$arg,$after) = PT_NEXTCOMMAND($code,"PT_WAIT_WHILE"); ($success,$before,$arg,$after) = PT_NEXTCOMMAND($block,"PT_WAIT_WHILE");
if ($success) { if ($success) {
$code=$before.$thread."->{PT_THREAD_STATE} = 'PT_LABEL_$counter'; PT_LABEL_$counter: return PT_WAITING if ($arg);".$after; $block=$before.$thread."->{PT_THREAD_POSITION} = 'PT_LABEL_$counter'; PT_LABEL_$counter: return PT_WAITING if ($arg);".$after;
$counter++; $counter++;
next; next;
} }
($success,$before,$arg,$after) = PT_NEXTCOMMAND($code,"PT_WAIT_THREAD"); ($success,$before,$arg,$after) = PT_NEXTCOMMAND($block,"PT_WAIT_THREAD");
if ($success) { if ($success) {
$code=$before."PT_WAIT_WHILE(PT_SCHEDULE(".$arg."));".$after; $block=$before."PT_WAIT_WHILE(PT_SCHEDULE(".$arg."));".$after;
next; next;
} }
($success,$before,$arg,$after) = PT_NEXTCOMMAND($code,"PT_SPAWN"); ($success,$before,$arg,$after) = PT_NEXTCOMMAND($block,"PT_SPAWN");
if ($success) { if ($success) {
$code=$before.$arg."->{PT_THREAD_STATE} = 0; PT_WAIT_THREAD($arg);".$after; $block=$before.$arg."->{PT_THREAD_POSITION} = 0; PT_WAIT_THREAD($arg);".$after;
next; next;
} }
($success,$before,$arg,$after) = PT_NEXTCOMMAND($code,"PT_EXIT"); ($success,$before,$arg,$after) = PT_NEXTCOMMAND($block,"PT_EXIT");
if ($success) { if ($success) {
$code=$before.$thread."->{PT_THREAD_STATE} = 0; ".$thread."->{PT_THREAD_RETURN} = $arg; return PT_EXITED;".$after; $block=$before.$thread."->{PT_THREAD_POSITION} = 0; ".$thread."->{PT_THREAD_RETURN} = $arg; return PT_EXITED;".$after;
next; next;
} }
if ($code =~ /PT_EXIT(\s*;|\s+)/s) { if ($block =~ /PT_EXIT(\s*;|\s+)/s) {
$code = $`.$thread."->{PT_THREAD_STATE} = 0; delete ".$thread."->{PT_THREAD_RETURN}; return PT_EXITED".$1.$'; $block = $`.$thread."->{PT_THREAD_POSITION} = 0; delete ".$thread."->{PT_THREAD_RETURN}; return PT_EXITED".$1.$';
next; next;
} }
if ($code =~ /PT_RESTART(\s*;|\s)/s) { if ($block =~ /PT_RESTART(\s*;|\s)/s) {
$code = $`.$thread."->{PT_THREAD_STATE} = 0; return PT_WAITING;".$1.$'; $block = $`.$thread."->{PT_THREAD_POSITION} = 0; return PT_WAITING;".$1.$';
next; next;
} }
if ($code =~ /PT_END\s*;/s) {
$code = $`.$thread."->{PT_THREAD_STATE} = 0; delete ".$thread."->{PT_THREAD_RETURN}; return PT_ENDED; }; die \$\@ if \$\@; return \$PT_THREAD_STATE;".$';
}
last; last;
} }
$code = $beforeblock.$block.$afterblock;
} else {
die "PT_END expected"
}
next; next;
} }
last; last;