From 1a73078526fc8f73a8b83fea983c45741fa9e382 Mon Sep 17 00:00:00 2001 From: ntruchsess <> Date: Fri, 18 Jul 2014 21:50:39 +0000 Subject: [PATCH] OWX_SER: implement DevIo-based communication and reconnect git-svn-id: https://svn.fhem.de/fhem/trunk/fhem@6271 2b470e98-0d58-463d-a4d8-8e2adae1ed80 --- FHEM/00_OWX_ASYNC.pm | 62 ++++++++++------------------- FHEM/OWX_DS2480.pm | 30 +++----------- FHEM/OWX_SER.pm | 95 ++++++++++++++++++++------------------------ 3 files changed, 68 insertions(+), 119 deletions(-) diff --git a/FHEM/00_OWX_ASYNC.pm b/FHEM/00_OWX_ASYNC.pm index 76a22de5d..806ab3cf4 100644 --- a/FHEM/00_OWX_ASYNC.pm +++ b/FHEM/00_OWX_ASYNC.pm @@ -84,7 +84,6 @@ if( $^O =~ /Win/ ) { use Time::HiRes qw( gettimeofday tv_interval ); -require "$main::attr{global}{modpath}/FHEM/DevIo.pm"; sub Log3($$$); use vars qw{%owg_family %gets %sets $owx_async_version $owx_async_debug}; @@ -275,48 +274,25 @@ sub OWX_ASYNC_Ready ($) { }; sub OWX_ASYNC_Read ($) { - my $hash = shift; + my ($hash) = @_; Log3 ($hash->{NAME},5,"OWX_ASYNC_Read") if ($owx_async_debug > 2); - OWX_ASYNC_Poll($hash); + if (defined $hash->{ASYNC}) { + $hash->{ASYNC}->poll($hash); + }; OWX_ASYNC_RunTasks($hash); }; -sub OWX_ASYNC_Poll ($) { - my $hash = shift; - Log3 ($hash->{NAME},5,"OWX_ASYNC_Poll") if ($owx_async_debug > 2); - if (defined $hash->{ASYNC}) { - $hash->{ASYNC}->poll($hash); - }; -}; - sub OWX_ASYNC_Disconnect($) { - my ($hash) = @_; - my $async = $hash->{ASYNC}; - Log3 ($hash->{NAME},3, "OWX_ASYNC_Disconnect"); - if (defined $async) { - $async->exit($hash); - }; - my $times = AttrVal($hash->{NAME},"timeout",5000) / 50; #timeout in ms, defaults to 1 sec? - for (my $i=0;$i<$times;$i++) { - OWX_ASYNC_Poll($hash); - if ($hash->{STATE} ne "Active") { - last; - } - }; + my ($hash) = @_; + my $async = $hash->{ASYNC}; + Log3 ($hash->{NAME},3, "OWX_ASYNC_Disconnect"); + if (defined $async) { + $async->exit($hash); + delete $hash->{ASYNC}; + }; + $hash->{STATE} = "disconnected" if $hash->{STATE} eq "Active"; }; -sub OWX_ASYNC_Disconnected($) { - my ($hash) = @_; - Log3 ($hash->{NAME},4, "OWX_ASYNC_Disconnected"); - if ($hash->{ASYNC} and $hash->{ASYNC} != $hash->{OWX}) { - delete $hash->{ASYNC}; - }; - if (my $owx = $hash->{OWX}) { - $owx->Disconnect($hash); - }; - $hash->{STATE} = "disconnected" if $hash->{STATE} eq "Active"; -}; - ######################################################################################## # # OWX_ASYNC_Alarms - Initiate search for devices on the 1-Wire bus which have the alarm flag set @@ -711,12 +687,12 @@ sub OWX_ASYNC_Init ($) { RemoveInternalTimer($hash); if (defined ($hash->{ASNYC})) { - $hash->{ASYNC}->exit($hash); - $hash->{ASYNC} = undef; #TODO should we call delete on $hash->{ASYNC}? + $hash->{ASYNC}->exit($hash); + delete $hash->{ASYNC}; #TODO should we call delete on $hash->{ASYNC}? } #-- get the interface my $owx = $hash->{OWX}; - + if (defined $owx) { $hash->{INTERFACE} = $owx->{interface}; my $ret; @@ -729,9 +705,10 @@ sub OWX_ASYNC_Init ($) { $hash->{STATE} = "Init Failed: $err"; return "OWX_ASYNC_Init failed: $err"; }; - $hash->{ASYNC} = $ret; + return undef unless $ret; + $hash->{ASYNC} = $ret ; $hash->{ASYNC}->{debug} = $owx_async_debug; - $hash->{INTERFACE} = $owx->{interface}; + $hash->{INTERFACE} = $owx->{interface}; } else { return "OWX: Init called with undefined interface"; } @@ -1016,7 +993,8 @@ sub OWX_ASYNC_RunToCompletion($$) { OWX_ASYNC_Schedule($hash,$task); my $master = $hash->{TYPE} eq "OWX_ASYNC" ? $hash : $hash->{IODev}; do { - OWX_ASYNC_Poll($master); + die "interface $master->{INTERFACE} not active" unless defined $hash->{ASYNC}; + $hash->{ASYNC}->poll($hash); OWX_ASYNC_RunTasks($master); $task_state = $task->PT_STATE(); } while ($task_state == PT_INITIAL or $task_state == PT_WAITING or $task_state == PT_YIELDED); diff --git a/FHEM/OWX_DS2480.pm b/FHEM/OWX_DS2480.pm index 6bde1b8da..34acea8b0 100644 --- a/FHEM/OWX_DS2480.pm +++ b/FHEM/OWX_DS2480.pm @@ -86,24 +86,8 @@ sub block ($) { ######################################################################################## sub query ($$$) { - my ($serial,$cmd,$retlen) = @_; - my ($i,$j,$k,$l,$m,$n); - - #-- get hardware device - my $hwdevice = $serial->{hwdevice}; - - die "OWX_DS2480: query with no hwdevice" unless (defined $hwdevice); - - $hwdevice->baudrate($serial->{baud}); - $hwdevice->write_settings; - - main::Log3($serial->{name},5, "OWX_DS2480.query sending out: ".unpack ("H*",$cmd)); - - my $count_out = $hwdevice->write($cmd); - - die "OWX_DS2480: Write incomplete ".(defined $count_out ? $count_out : "undefined")." not equal ".(length($cmd))."" if (!(defined $count_out) or ($count_out ne length($cmd))); - + main::DevIo_SimpleWrite($serial->{hash},$cmd,0); $serial->{retlen} += $retlen; } @@ -119,16 +103,12 @@ sub query ($$$) { ######################################################################################## sub read() { - my $serial = shift; - my ($i,$j,$k); - - #-- get hardware device - my $hwdevice = $serial->{hwdevice}; - return undef unless (defined $hwdevice); + my ($serial) = @_; #-- read the data - my ($count_in, $string_part) = $hwdevice->read(255); - return undef if (not defined $count_in or not defined $string_part); + my $string_part = main::DevIo_DoSimpleRead($serial->{hash}); + return undef unless defined $string_part; + my $count_in = length ($string_part); $serial->{string_in} .= $string_part; $serial->{retcount} += $count_in; $serial->{num_reads}++; diff --git a/FHEM/OWX_SER.pm b/FHEM/OWX_SER.pm index 761ad3363..e905749ec 100644 --- a/FHEM/OWX_SER.pm +++ b/FHEM/OWX_SER.pm @@ -30,6 +30,8 @@ use warnings; use vars qw/@ISA/; +require "$main::attr{global}{modpath}/FHEM/DevIo.pm"; + use Time::HiRes qw( gettimeofday ); use ProtoThreads; no warnings 'deprecated'; @@ -44,8 +46,6 @@ sub new() { my $class = shift; my $self = { interface => "serial", - #-- baud rate serial interface - baud => 9600, #-- 16 byte search string search => [0,0,0,0 ,0,0,0,0, 0,0,0,0, 0,0,0,0], ROM_ID => [0,0,0,0 ,0,0,0,0], @@ -64,7 +64,15 @@ sub new() { sub poll($) { my ( $self ) = @_; - $self->read(); + my $hash = $self->{hash}; + if(defined($hash->{FD})) { + my ($rin,$win); + vec($rin, $hash->{FD}, 1) = 1; + vec($win, $hash->{FD}, 1) = 1; + if (select($rin, $win, $rin | $win, 2)) { #TODO: implement attribute based timeout + main::OWX_ASYNC_Disconnect($hash) unless $self->read(); + } + } } ######################################################################################## @@ -82,17 +90,17 @@ sub poll($) { ######################################################################################## sub Define ($$) { - my ($self,$hash,$def) = @_; - my @a = split("[ \t][ \t]*", $def); + my ($self,$hash,$def) = @_; + my @a = split("[ \t][ \t]*", $def); - $self->{name} = $hash->{NAME}; + $self->{name} = $hash->{NAME}; + + #-- check syntax + if(int(@a) < 3){ + return "OWX_SER: Syntax error - must be define OWX " + } + my $dev = $a[2]; - #-- check syntax - if(int(@a) < 3){ - return "OWX_SER: Syntax error - must be define OWX " - } - my $dev = $a[2]; - #-- when the specified device name contains @ already, use it as supplied if ( $dev !~ m/\@\d*/ ){ $hash->{DeviceName} = $dev."\@9600"; @@ -100,7 +108,10 @@ sub Define ($$) { my ($device,$baudrate) = split('@',$dev); #-- let fhem.pl MAIN call OWX_Ready when setup is done. $main::readyfnlist{"$hash->{NAME}.$device"} = $hash; - + + $self->{baud} = $baudrate ? $baudrate : 9600; + $self->{hash} = $hash; + return undef; } @@ -153,13 +164,6 @@ sub get_pt_execute($$$$) { PT_BEGIN($thread); $thread->{writedata} = $writedata; - #-- get the interface - my $interface = $self->{interface}; - my $hwdevice = $self->{hwdevice}; - unless (defined $hwdevice) { - PT_EXIT; - } - $self->reset() if ($reset); if (defined $writedata or $numread) { @@ -263,30 +267,18 @@ sub get_pt_discover() { # ######################################################################################## -sub initialize($) { - my ($self,$hash) = @_; +sub initialize() { + my ($self) = @_; my ($i,$j,$k,$l,$res,$ret,$ress); #-- Second step in case of serial device: open the serial device to test it + my $hash = $self->{hash}; my $msg = "OWX_SER: Serial device $hash->{DeviceName}"; - main::DevIo_OpenDev($hash,0,undef); + main::DevIo_OpenDev($hash,$self->{reopen},undef); + return undef unless $hash->{STATE} eq "opened"; + my $hwdevice = $hash->{USBDev}; - if(!defined($hwdevice)){ - die $msg." not defined: $!"; - } else { - main::Log3($hash->{NAME},2,$msg." defined"); - } - - $hwdevice->reset_error(); - $hwdevice->baudrate(9600); - $hwdevice->databits(8); - $hwdevice->parity('none'); - $hwdevice->stopbits(1); - $hwdevice->handshake('none'); - $hwdevice->write_settings; - #-- store with OWX device - $self->{hwdevice} = $hwdevice; - #force master reset in DS2480 + $hwdevice->reset_error(); $hwdevice->purge_all; $hwdevice->baudrate(4800); $hwdevice->write_settings; @@ -294,7 +286,7 @@ sub initialize($) { select(undef,undef,undef,0.5); #-- Third step detect busmaster on serial interface - + my $name = $self->{name}; my $ress0 = "OWX_SER::Detect 1-Wire bus $name: interface "; $ress = $ress0; @@ -303,16 +295,15 @@ sub initialize($) { require "$main::attr{global}{modpath}/FHEM/OWX_DS2480.pm"; my $ds2480 = OWX_DS2480->new($self); - + #-- timing byte for DS2480 $ds2480->start_query(); + $hwdevice->baudrate(9600); + $hwdevice->write_settings; $ds2480->query("\xC1",1); - eval { #ignore timeout - do { - $ds2480->read(); - } while (!$ds2480->response_ready()); - }; - + $hwdevice->baudrate($self->{baud}); + $hwdevice->write_settings; + #-- Max 4 tries to detect an interface for($l=0;$l<100;$l++) { #-- write 1-Wire bus (Fig. 2 of Maxim AN192) @@ -377,11 +368,11 @@ sub initialize($) { } } -sub Disconnect($) { - my ($self,$hash) = @_; - main::DevIo_Disconnected($hash); - delete $self->{hwdevice}; - $self->{interface} = "serial"; +sub exit($) { + my ($self) = @_; + main::DevIo_Disconnected($self->{hash}); + $self->{interface} = "serial"; + $self->{reopen} = 1; } ########################################################################################