OWX_SER: implement DevIo-based communication and reconnect

git-svn-id: https://svn.fhem.de/fhem/trunk/fhem@6271 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
ntruchsess 2014-07-18 21:50:39 +00:00
parent 3fd88da9b0
commit 1a73078526
3 changed files with 68 additions and 119 deletions

View File

@ -84,7 +84,6 @@ if( $^O =~ /Win/ ) {
use Time::HiRes qw( gettimeofday tv_interval ); use Time::HiRes qw( gettimeofday tv_interval );
require "$main::attr{global}{modpath}/FHEM/DevIo.pm";
sub Log3($$$); sub Log3($$$);
use vars qw{%owg_family %gets %sets $owx_async_version $owx_async_debug}; use vars qw{%owg_family %gets %sets $owx_async_version $owx_async_debug};
@ -275,18 +274,12 @@ sub OWX_ASYNC_Ready ($) {
}; };
sub OWX_ASYNC_Read ($) { sub OWX_ASYNC_Read ($) {
my $hash = shift; my ($hash) = @_;
Log3 ($hash->{NAME},5,"OWX_ASYNC_Read") if ($owx_async_debug > 2); Log3 ($hash->{NAME},5,"OWX_ASYNC_Read") if ($owx_async_debug > 2);
OWX_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}) { if (defined $hash->{ASYNC}) {
$hash->{ASYNC}->poll($hash); $hash->{ASYNC}->poll($hash);
}; };
OWX_ASYNC_RunTasks($hash);
}; };
sub OWX_ASYNC_Disconnect($) { sub OWX_ASYNC_Disconnect($) {
@ -295,25 +288,8 @@ sub OWX_ASYNC_Disconnect($) {
Log3 ($hash->{NAME},3, "OWX_ASYNC_Disconnect"); Log3 ($hash->{NAME},3, "OWX_ASYNC_Disconnect");
if (defined $async) { if (defined $async) {
$async->exit($hash); $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;
}
};
};
sub OWX_ASYNC_Disconnected($) {
my ($hash) = @_;
Log3 ($hash->{NAME},4, "OWX_ASYNC_Disconnected");
if ($hash->{ASYNC} and $hash->{ASYNC} != $hash->{OWX}) {
delete $hash->{ASYNC}; delete $hash->{ASYNC};
}; };
if (my $owx = $hash->{OWX}) {
$owx->Disconnect($hash);
};
$hash->{STATE} = "disconnected" if $hash->{STATE} eq "Active"; $hash->{STATE} = "disconnected" if $hash->{STATE} eq "Active";
}; };
@ -712,7 +688,7 @@ sub OWX_ASYNC_Init ($) {
RemoveInternalTimer($hash); RemoveInternalTimer($hash);
if (defined ($hash->{ASNYC})) { if (defined ($hash->{ASNYC})) {
$hash->{ASYNC}->exit($hash); $hash->{ASYNC}->exit($hash);
$hash->{ASYNC} = undef; #TODO should we call delete on $hash->{ASYNC}? delete $hash->{ASYNC}; #TODO should we call delete on $hash->{ASYNC}?
} }
#-- get the interface #-- get the interface
my $owx = $hash->{OWX}; my $owx = $hash->{OWX};
@ -729,6 +705,7 @@ sub OWX_ASYNC_Init ($) {
$hash->{STATE} = "Init Failed: $err"; $hash->{STATE} = "Init Failed: $err";
return "OWX_ASYNC_Init failed: $err"; return "OWX_ASYNC_Init failed: $err";
}; };
return undef unless $ret;
$hash->{ASYNC} = $ret ; $hash->{ASYNC} = $ret ;
$hash->{ASYNC}->{debug} = $owx_async_debug; $hash->{ASYNC}->{debug} = $owx_async_debug;
$hash->{INTERFACE} = $owx->{interface}; $hash->{INTERFACE} = $owx->{interface};
@ -1016,7 +993,8 @@ sub OWX_ASYNC_RunToCompletion($$) {
OWX_ASYNC_Schedule($hash,$task); OWX_ASYNC_Schedule($hash,$task);
my $master = $hash->{TYPE} eq "OWX_ASYNC" ? $hash : $hash->{IODev}; my $master = $hash->{TYPE} eq "OWX_ASYNC" ? $hash : $hash->{IODev};
do { do {
OWX_ASYNC_Poll($master); die "interface $master->{INTERFACE} not active" unless defined $hash->{ASYNC};
$hash->{ASYNC}->poll($hash);
OWX_ASYNC_RunTasks($master); OWX_ASYNC_RunTasks($master);
$task_state = $task->PT_STATE(); $task_state = $task->PT_STATE();
} while ($task_state == PT_INITIAL or $task_state == PT_WAITING or $task_state == PT_YIELDED); } while ($task_state == PT_INITIAL or $task_state == PT_WAITING or $task_state == PT_YIELDED);

View File

@ -86,24 +86,8 @@ sub block ($) {
######################################################################################## ########################################################################################
sub query ($$$) { sub query ($$$) {
my ($serial,$cmd,$retlen) = @_; my ($serial,$cmd,$retlen) = @_;
my ($i,$j,$k,$l,$m,$n); main::DevIo_SimpleWrite($serial->{hash},$cmd,0);
#-- 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)));
$serial->{retlen} += $retlen; $serial->{retlen} += $retlen;
} }
@ -119,16 +103,12 @@ sub query ($$$) {
######################################################################################## ########################################################################################
sub read() { sub read() {
my $serial = shift; my ($serial) = @_;
my ($i,$j,$k);
#-- get hardware device
my $hwdevice = $serial->{hwdevice};
return undef unless (defined $hwdevice);
#-- read the data #-- read the data
my ($count_in, $string_part) = $hwdevice->read(255); my $string_part = main::DevIo_DoSimpleRead($serial->{hash});
return undef if (not defined $count_in or not defined $string_part); return undef unless defined $string_part;
my $count_in = length ($string_part);
$serial->{string_in} .= $string_part; $serial->{string_in} .= $string_part;
$serial->{retcount} += $count_in; $serial->{retcount} += $count_in;
$serial->{num_reads}++; $serial->{num_reads}++;

View File

@ -30,6 +30,8 @@ use warnings;
use vars qw/@ISA/; use vars qw/@ISA/;
require "$main::attr{global}{modpath}/FHEM/DevIo.pm";
use Time::HiRes qw( gettimeofday ); use Time::HiRes qw( gettimeofday );
use ProtoThreads; use ProtoThreads;
no warnings 'deprecated'; no warnings 'deprecated';
@ -44,8 +46,6 @@ sub new() {
my $class = shift; my $class = shift;
my $self = { my $self = {
interface => "serial", interface => "serial",
#-- baud rate serial interface
baud => 9600,
#-- 16 byte search string #-- 16 byte search string
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],
ROM_ID => [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($) { sub poll($) {
my ( $self ) = @_; 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();
}
}
} }
######################################################################################## ########################################################################################
@ -101,6 +109,9 @@ sub Define ($$) {
#-- let fhem.pl MAIN call OWX_Ready when setup is done. #-- let fhem.pl MAIN call OWX_Ready when setup is done.
$main::readyfnlist{"$hash->{NAME}.$device"} = $hash; $main::readyfnlist{"$hash->{NAME}.$device"} = $hash;
$self->{baud} = $baudrate ? $baudrate : 9600;
$self->{hash} = $hash;
return undef; return undef;
} }
@ -153,13 +164,6 @@ sub get_pt_execute($$$$) {
PT_BEGIN($thread); PT_BEGIN($thread);
$thread->{writedata} = $writedata; $thread->{writedata} = $writedata;
#-- get the interface
my $interface = $self->{interface};
my $hwdevice = $self->{hwdevice};
unless (defined $hwdevice) {
PT_EXIT;
}
$self->reset() if ($reset); $self->reset() if ($reset);
if (defined $writedata or $numread) { if (defined $writedata or $numread) {
@ -263,30 +267,18 @@ sub get_pt_discover() {
# #
######################################################################################## ########################################################################################
sub initialize($) { sub initialize() {
my ($self,$hash) = @_; my ($self) = @_;
my ($i,$j,$k,$l,$res,$ret,$ress); my ($i,$j,$k,$l,$res,$ret,$ress);
#-- Second step in case of serial device: open the serial device to test it #-- 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}"; 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}; 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 #force master reset in DS2480
$hwdevice->reset_error();
$hwdevice->purge_all; $hwdevice->purge_all;
$hwdevice->baudrate(4800); $hwdevice->baudrate(4800);
$hwdevice->write_settings; $hwdevice->write_settings;
@ -306,12 +298,11 @@ sub initialize($) {
#-- timing byte for DS2480 #-- timing byte for DS2480
$ds2480->start_query(); $ds2480->start_query();
$hwdevice->baudrate(9600);
$hwdevice->write_settings;
$ds2480->query("\xC1",1); $ds2480->query("\xC1",1);
eval { #ignore timeout $hwdevice->baudrate($self->{baud});
do { $hwdevice->write_settings;
$ds2480->read();
} while (!$ds2480->response_ready());
};
#-- Max 4 tries to detect an interface #-- Max 4 tries to detect an interface
for($l=0;$l<100;$l++) { for($l=0;$l<100;$l++) {
@ -377,11 +368,11 @@ sub initialize($) {
} }
} }
sub Disconnect($) { sub exit($) {
my ($self,$hash) = @_; my ($self) = @_;
main::DevIo_Disconnected($hash); main::DevIo_Disconnected($self->{hash});
delete $self->{hwdevice};
$self->{interface} = "serial"; $self->{interface} = "serial";
$self->{reopen} = 1;
} }
######################################################################################## ########################################################################################