diff --git a/fhem/FHEM/OWX_DS2480.pm b/fhem/FHEM/OWX_DS2480.pm index a9bed588e..738a9ad3e 100644 --- a/fhem/FHEM/OWX_DS2480.pm +++ b/fhem/FHEM/OWX_DS2480.pm @@ -28,6 +28,8 @@ package OWX_DS2480; use strict; use warnings; use Time::HiRes qw( gettimeofday tv_interval usleep ); +use ProtoThreads; +no warnings 'deprecated'; use vars qw/@ISA/; @ISA='OWX_SER'; @@ -38,6 +40,92 @@ sub new($) { return bless $serial,$class; } +######################################################################################## +# +# 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, $dev, $writedata, $numread) = @_; + return PT_THREAD(sub { + my ($thread) = @_; + + PT_BEGIN($thread); + + $self->reset() if ($reset); + + if (defined $writedata or $numread) { + + my $select; + + #-- has match ROM part + if( $dev ) { + + #-- ID of the device + my $owx_rnf = substr($dev,3,12); + my $owx_f = substr($dev,0,2); + + #-- 8 byte 1-Wire device address + my @rom_id =(0,0,0,0 ,0,0,0,0); + #-- from search string to byte id + $dev=~s/\.//g; + for(my $i=0;$i<8;$i++){ + $rom_id[$i]=hex(substr($dev,2*$i,2)); + } + $select=sprintf("\x55%c%c%c%c%c%c%c%c",@rom_id); + #-- has no match ROM part, issue skip ROM command (0xCC:) + } else { + $select="\xCC"; + } + if (defined $writedata) { + $select.=$writedata; + } + #-- has receive data part + if( $numread ) { + #$numread += length($data); + for( my $i=0;$i<$numread;$i++){ + $select .= "\xFF"; + }; + } + + #-- for debugging + if( $main::owx_async_debug > 1){ + main::Log3($self->{name},5,"OWX_SER::Execute: Sending out ".unpack ("H*",$select)); + } + $self->block($select); + } + + PT_WAIT_UNTIL($self->response_ready()); + + if ($reset and !$self->reset_response()) { + die "reset failure"; + } + + my $res = $self->{string_in}; + #-- for debugging + if( $main::owx_async_debug > 1){ + main::Log3($self->{name},5,"OWX_SER::Execute: Receiving ".unpack ("H*",$res)); + } + + if (defined $res) { + my $writelen = defined $writedata ? split (//,$writedata) : 0; + my @result = split (//, $res); + my $readdata = 9+$writelen < @result ? substr($res,9+$writelen) : ""; + PT_EXIT($readdata); + } + PT_END; + }); +} + ######################################################################################## # # The following subroutines in alphabetical order are only for a DS2480 bus interface @@ -209,200 +297,97 @@ sub reset_response() { # ######################################################################################## -sub search ($) { - my ($serial,$mode)=@_; - - my ($sp1,$sp2,$search_direction,$id_bit_number); - - #-- Response search data parsing operates bytewise - $id_bit_number = 1; - - #select(undef,undef,undef,0.5); - - #-- clear 16 byte of search data - @{$serial->{search}}=(0,0,0,0 ,0,0,0,0, 0,0,0,0, 0,0,0,0); - #-- Output search data construction (Fig. 9 of Maxim AN192) - # operates on a 16 byte search response = 64 pairs of two bits - while ( $id_bit_number <= 64) { - #-- address single bits in a 16 byte search string - my $newcpos = int(($id_bit_number-1)/4); - my $newimsk = ($id_bit_number-1)%4; - #-- address single bits in a 8 byte id string - my $newcpos2 = int(($id_bit_number-1)/8); - my $newimsk2 = ($id_bit_number-1)%8; +sub pt_next ($$) { - if( $id_bit_number <= $serial->{LastDiscrepancy}){ - #-- first use the ROM ID bit to set the search direction - if( $id_bit_number < $serial->{LastDiscrepancy} ) { - $search_direction = ($serial->{ROM_ID}->[$newcpos2]>>$newimsk2) & 1; - #-- at the last discrepancy search into 1 direction anyhow - } else { - $search_direction = 1; - } - #-- fill into search data; - @{$serial->{search}}[$newcpos]+=$search_direction<<(2*$newimsk+1); - } - #--increment number - $id_bit_number++; - } - #-- issue data mode \xE1, the normal search command \xF0 or the alarm search command \xEC - # and the command mode \xE3 / start accelerator \xB5 - if( $mode ne "alarm" ){ - $sp1 = "\xE1\xF0\xE3\xB5"; - } else { - $sp1 = "\xE1\xEC\xE3\xB5"; - } - #-- issue data mode \xE1, device ID, command mode \xE3 / end accelerator \xA5 - $sp2=sprintf("\xE1%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c\xE3\xA5",@{$serial->{search}}); - $serial->reset(); - $serial->query($sp1,1); - $serial->query($sp2,16); -} + my ($serial,$context,$mode)=@_; -sub search_response($) { - my ($serial) = @_; - - return undef unless $serial->reset_response(); - - my $response = substr($serial->{string_in},1); - #-- interpret the return data - if( length($response)!=16 ) { - main::Log3($serial->{name},4, "OWX_DS2480: Search 2nd return has wrong parameter with length = ".(length($response)."")); - return 0; - } - #-- Response search data parsing (Fig. 11 of Maxim AN192) - # operates on a 16 byte search response = 64 pairs of two bits my $id_bit_number = 1; - #-- clear 8 byte of device id for current search - $serial->{ROM_ID} = [0,0,0,0 ,0,0,0,0]; + my $rom_byte_number = 0; + my $rom_byte_mask = 1; + my $last_zero = 0; + my ($sp1,$sp2,$pt_query,$search_direction); - while ( $id_bit_number <= 64) { - #-- adress single bits in a 16 byte string - my $newcpos = int(($id_bit_number-1)/4); - my $newimsk = ($id_bit_number-1)%4; - - #-- retrieve the new ROM_ID bit - my $newchar = substr($response,$newcpos,1); - - #-- these are the new bits - my $newibit = (( ord($newchar) >> (2*$newimsk) ) & 2) / 2; - my $newdbit = ( ord($newchar) >> (2*$newimsk) ) & 1; - - #-- output for test purpose - #print "id_bit_number=$id_bit_number => newcpos=$newcpos, newchar=0x".int(ord($newchar)/16). - # ".".int(ord($newchar)%16)." r$id_bit_number=$newibit d$id_bit_number=$newdbit\n"; - - #-- discrepancy=1 and ROM_ID=0 - if( ($newdbit==1) and ($newibit==0) ){ - $serial->{LastDiscrepancy}=$id_bit_number; - if( $id_bit_number < 9 ){ - $serial->{LastFamilyDiscrepancy}=$id_bit_number; - } - } - #-- fill into device data; one char per 8 bits - $serial->{ROM_ID}->[int(($id_bit_number-1)/8)]+=$newibit<<(($id_bit_number-1)%8); + return PT_THREAD(sub { + my ( $thread ) = @_; + PT_BEGIN($thread); + #-- clear 16 byte of search data + $context->{search} = [0,0,0,0 ,0,0,0,0, 0,0,0,0, 0,0,0,0]; + #-- Output search data construction (Fig. 9 of Maxim AN192) + # operates on a 16 byte search response = 64 pairs of two bits + while ( $id_bit_number <= 64) { + #-- address single bits in a 16 byte search string + my $newcpos = int(($id_bit_number-1)/4); + my $newimsk = ($id_bit_number-1)%4; + #-- address single bits in a 8 byte id string + my $newcpos2 = int(($id_bit_number-1)/8); + my $newimsk2 = ($id_bit_number-1)%8; - #-- increment number - $id_bit_number++; - } - return 1; -} - -######################################################################################## -# -# Level_2480 - Change power level (Fig. 13 of Maxim AN192) -# -# Parameter hash = hash of bus master, newlevel = "normal" or something else -# -# Return 1 : OK -# 0 : not OK -# -######################################################################################## - -sub Level_2480 ($) { - my ($self,$newlevel) =@_; - my $cmd=""; - my $retlen=0; - #-- if necessary, prepend E3 character for command mode - $cmd = "\xE3"; - - #-- return to normal level - if( $newlevel eq "normal" ){ - $cmd=$cmd."\xF1\xED\xF1"; - $retlen+=3; - #-- write 1-Wire bus - my $res = $self->Query_2480($cmd,$retlen); - return undef if (not defined $res); - #-- process result - my $r1 = ord(substr($res,0,1)) & 236; - my $r2 = ord(substr($res,1,1)) & 236; - if( ($r1 eq 236) && ($r2 eq 236) ){ - main::Log3($self->{name},5, "OWX_SER: Level change to normal OK"); - return 1; + if( $id_bit_number <= $context->{LastDiscrepancy}){ + #-- first use the ROM ID bit to set the search direction + if( $id_bit_number < $context->{LastDiscrepancy} ) { + $search_direction = ($context->{ROM_ID}->[$newcpos2]>>$newimsk2) & 1; + #-- at the last discrepancy search into 1 direction anyhow + } else { + $search_direction = 1; + } + #-- fill into search data; + $context->{search}->[$newcpos]+=$search_direction<<(2*$newimsk+1); + } + #--increment number + $id_bit_number++; + } + #-- issue data mode \xE1, the normal search command \xF0 or the alarm search command \xEC + # and the command mode \xE3 / start accelerator \xB5 + if( $mode ne "alarm" ){ + $sp1 = "\xE1\xF0\xE3\xB5"; } else { - main::Log3($self->{name},4, "OWX_SER: Failed to change to normal level"); - return 0; + $sp1 = "\xE1\xEC\xE3\xB5"; } - #-- start pulse - } else { - $cmd=$cmd."\x3F\xED"; - $retlen+=2; - #-- write 1-Wire bus - my $res = $self->Query_2480($cmd,$retlen); - return undef if (not defined $res); - #-- process result - if( $res eq "\x3E" ){ - main::Log3($self->{name},5, "OWX_SER: Level change OK"); - return 1; - } else { - main::Log3($self->{name},4, "OWX_SER: Failed to change level"); - return 0; + #-- issue data mode \xE1, device ID, command mode \xE3 / end accelerator \xA5 + $sp2=sprintf("\xE1%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c\xE3\xA5",@{$context->{search}}); + $serial->reset(); + $serial->query($sp1,1); + $serial->query($sp2,16); + PT_WAIT_UNTIL($serial->response_ready()); + die "reset failed" unless $serial->reset_response(); + + my $response = substr($serial->{string_in},1); + #-- interpret the return data + if( length($response)!=16 ) { + die "OWX_DS2480: Search 2nd return has wrong parameter with length = ".(length($response)."")); } - } -} + #-- Response search data parsing (Fig. 11 of Maxim AN192) + # operates on a 16 byte search response = 64 pairs of two bits + my $id_bit_number = 1; + #-- clear 8 byte of device id for current search + $context->{ROM_ID} = [0,0,0,0 ,0,0,0,0]; -######################################################################################## -# -# WriteBytePower_2480 - Send byte to bus with power increase (Fig. 16 of Maxim AN192) -# -# Parameter hash = hash of bus master, dbyte = byte to send -# -# Return 1 : OK -# 0 : not OK -# -######################################################################################## + while ( $id_bit_number <= 64) { + #-- adress single bits in a 16 byte string + my $newcpos = int(($id_bit_number-1)/4); + my $newimsk = ($id_bit_number-1)%4; -sub WriteBytePower_2480 ($) { + #-- retrieve the new ROM_ID bit + my $newchar = substr($response,$newcpos,1); - my ($self,$dbyte) =@_; - - my $cmd="\x3F"; - my $ret="\x3E"; - #-- if necessary, prepend \xE3 character for command mode - $cmd = "\xE3".$cmd; - - #-- distribute the bits of data byte over several command bytes - for (my $i=0;$i<8;$i++){ - my $newbit = (ord($dbyte) >> $i) & 1; - my $newchar = 133 | ($newbit << 4); - my $newchar2 = 132 | ($newbit << 4) | ($newbit << 1) | $newbit; - #-- last command byte still different - if( $i == 7){ - $newchar = $newchar | 2; + #-- these are the new bits + my $newibit = (( ord($newchar) >> (2*$newimsk) ) & 2) / 2; + my $newdbit = ( ord($newchar) >> (2*$newimsk) ) & 1; + + #-- discrepancy=1 and ROM_ID=0 + if( ($newdbit==1) and ($newibit==0) ){ + $context->{LastDiscrepancy}=$id_bit_number; + if( $id_bit_number < 9 ){ + $context->{LastFamilyDiscrepancy}=$id_bit_number; + } + } + #-- fill into device data; one char per 8 bits + $context->{ROM_ID}->[int(($id_bit_number-1)/8)]+=$newibit<<(($id_bit_number-1)%8); + + #-- increment number + $id_bit_number++; } - $cmd = $cmd.chr($newchar); - $ret = $ret.chr($newchar2); - } - #-- write 1-Wire bus - my $res = $self->Query($cmd); - #-- process result - if( $res eq $ret ){ - main::Log3($self->{name},5, "OWX_SER::WriteBytePower OK"); - return 1; - } else { - main::Log3($self->{name},4, "OWX_SER::WriteBytePower failure"); - return 0; - } + }); } 1; diff --git a/fhem/FHEM/OWX_DS9097.pm b/fhem/FHEM/OWX_DS9097.pm new file mode 100644 index 000000000..48d7e2a43 --- /dev/null +++ b/fhem/FHEM/OWX_DS9097.pm @@ -0,0 +1,287 @@ +######################################################################################## +# +# OWX_DS2480.pm +# +# FHEM module providing hardware dependent functions for the DS9097 interface of OWX +# +# Prof. Dr. Peter A. Henning +# Norbert Truchsess +# +# $Id$ +# +######################################################################################## +# +# Provides the following methods for OWX +# +# Alarms +# Complex +# Define +# Discover +# Init +# Reset +# Verify +# +######################################################################################## + +package OWX_DS9097; + +use strict; +use warnings; +use Time::HiRes qw( gettimeofday ); + +use vars qw/@ISA/; +@ISA='OWX_SER'; + +use ProtoThreads; +no warnings 'deprecated'; + +sub new($) { + my ($class,$serial) = @_; + return bless $serial,$class; +} + +######################################################################################## +# +# 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, $dev, $writedata, $numread) = @_; + my $pt_query; + return PT_THREAD(sub { + my ($thread) = @_; + my $select; + PT_BEGIN($thread); + $self->reset() if ($reset); + if (defined $writedata or $numread) { + #-- has match ROM part + if( $dev ) { + #-- 8 byte 1-Wire device address + my @rom_id; + #-- from search string to byte id + $dev=~s/\.//g; + for(my $i=0;$i<8;$i++){ + $rom_id[$i]=hex(substr($dev,2*$i,2)); + } + $select=sprintf("\x55%c%c%c%c%c%c%c%c",@rom_id); + #-- has no match ROM part, issue skip ROM command (0xCC:) + } else { + $select="\xCC"; + } + if (defined $writedata) { + $select.=$writedata; + } + #-- for debugging + if( $main::owx_async_debug > 1){ + main::Log3($self->{name},5,"OWX_DS9097::pt_execute: Sending out ".unpack ("H*",$select)); + } + $self->block($select); + } + #-- has receive data part + if( $numread ) { + $select = ""; + #$numread += length($data); + for( my $i=0;$i<$numread;$i++){ + $select .= "11111111"; + }; + $pt_query = $self->pt_query($select); + PT_WAIT_THREAD($pt_query); + die $pt_query->PT_CAUSE() if ($pt_query->PT_STATE() == PT_ERROR || $pt_query->PT_STATE() == PT_CANCELED); + my $res = pack "B*",$pt_query->PT_RETVAL(); + main::Log3($self->{name},5,"OWX_DS9097::pt_execute: Receiving ".unpack ("H*",$res)) if( $main::owx_async_debug > 1); + PT_EXIT($res); + } else { + PT_EXIT(""); + } + PT_END; + }); +} + +sub reset() { + my ( $serial ) = @_; + + if (defined (my $hwdevice = $serial->{hash}->{USBDev})) { + + $hwdevice->baudrate(9600); + $hwdevice->write_settings; + $hwdevice->write("0xF0"); + + while ($serial->poll()) {}; + + $hwdevice->baudrate(115200); + $hwdevice->write_settings; + + } +} + +sub block($) { + my ( $serial, $block ) = @_; + if (defined (my $hwdevice = $serial->{hash}->{USBDev})) { + main::Log3($serial->{name},5, "OWX_DS9097 block: ".unpack "H*",$block) if ( $main::owx_async_debug > 1 ); + foreach my $bit (split //,unpack "B*",$block) { + $serial->bit($bit); + } + } else { + die "no USBDev"; + } +} + +sub bit($) { + my ( $serial, $bit ) = @_; + if (defined (my $hwdevice = $serial->{hash}->{USBDev})) { + my $sp1 = $bit == 1 ? "\xFF" : "\x00"; + main::Log3($serial->{name},5, sprintf("OWX_DS9097 bit: %02X",ord($sp1))) if ( $main::owx_async_debug > 2 ); + $hwdevice->write($sp1); + } else { + die "no USBDev"; + } +} + +sub pt_query($) { + my ( $serial, $query ) = @_; + my @bitsout = split //,$query; + my $bitsin = ""; + my $bit; + return PT_THREAD(sub { + my ( $thread ) = @_; + PT_BEGIN($thread); + main::Log3($serial->{name},5, "OWX_DS9097 pt_query: ".$query) if( $main::owx_async_debug > 1 ); + while (defined ($bit = shift @bitsout)) { + while ($serial->poll()) {}; + $serial->{string_raw} = ""; + $serial->bit($bit); + PT_WAIT_UNTIL(length($serial->{string_raw}) > 0); + $bitsin .= substr($serial->{string_raw},0,1) eq ($bit == 1 ? "\xFF" : "\x00") ? "1" : "0"; + }; + PT_EXIT($bitsin); + PT_END; + }); +} + +sub read() { + my ($serial) = @_; + if (defined (my $hwdevice = $serial->{hash}->{USBDev})) { + my $string_part = $hwdevice->input(); + if (defined $string_part and length($string_part) > 0) { + $serial->{string_raw} .= $string_part; + main::Log3($serial->{name},5, "OWX_DS9097 read: Loop no. $serial->{num_reads}, Receiving: ".unpack("H*",$string_part)) if( $main::owx_async_debug > 1 ); + } elsif ($main::owx_async_debug > 2) { + main::Log3($serial->{name},5, "OWX_DS9097 read: Loop no. $serial->{num_reads}, no data read:"); + foreach my $i (0..6) { + my ($package, $filename, $line, $subroutine, $hasargs, $wantarray, $evaltext, $is_require, $hints, $bitmask, $hinthash) = caller($i); + main::Log3($serial->{name},5, "$subroutine $filename $line"); + } + } + } + return undef; +} + +sub response_ready() { + my ( $serial ) = @_; + $serial->{string_in} = pack "B*",$serial->{string_raw}; + main::Log3($serial->{name},5, "OWX_DS9097 response_ready: Received raw: ".$serial->{string_raw}) if( $main::owx_async_debug > 2 ); + main::Log3($serial->{name},5, "OWX_DS9097 response_ready: Received: ".unpack("H*",$serial->{string_in})) if( $main::owx_async_debug > 1 ); + return 1; +} + +sub pt_next ($$) { + + my ($serial,$context,$mode)=@_; + + my $id_bit_number = 1; + my $rom_byte_number = 0; + my $rom_byte_mask = 1; + my $last_zero = 0; + my ($pt_query,$search_direction); + + return PT_THREAD(sub { + my ( $thread ) = @_; + PT_BEGIN($thread); + $serial->reset(); + #-- issue the normal search command \xF0 or the alarm search command \xEC + if( $mode ne "alarm" ){ + $serial->block("\xF0"); + } else { + $serial->block("\xEC"); + } + #-- clear 8 byte of device id for current search + $context->{ROM_ID} = [0,0,0,0 ,0,0,0,0]; + + #-- Response search data parsing operates bitwise + + while ( $id_bit_number <= 64) { + #loop until through all ROM bytes 0-7 + $pt_query = $serial->pt_query("11"); + PT_WAIT_THREAD($pt_query); + die $pt_query->PT_CAUSE() if ($pt_query->PT_STATE() == PT_ERROR || $pt_query->PT_STATE() == PT_CANCELED); + my $ret = $pt_query->PT_RETVAL(); + + my ($id_bit,$cmp_id_bit) = split //,$ret; + + if( ($id_bit == 1) && ($cmp_id_bit == 1) ){ + main::Log3 ($serial->{name},5, "no devices present at id_bit_number=$id_bit_number"); + last; + } + if ( $id_bit != $cmp_id_bit ){ + $search_direction = $id_bit; + } else { + # hä ? if this discrepancy if before the Last Discrepancy + # on a previous next then pick the same as last time + if ( $id_bit_number < $context->{LastDiscrepancy} ){ + if (($context->{ROM_ID}->[$rom_byte_number] & $rom_byte_mask) > 0){ + $search_direction = 1; + } else { + $search_direction = 0; + } + } else { + # if equal to last pick 1, if not then pick 0 + if ($id_bit_number == $context->{LastDiscrepancy}){ + $search_direction = 1; + } else { + $search_direction = 0; + } + } + # if 0 was picked then record its position in LastZero + if ($search_direction == 0){ + $last_zero = $id_bit_number; + # check for Last discrepancy in family + if ($last_zero < 9) { + $context->{LastFamilyDiscrepancy} = $last_zero; + } + } + } + # set or clear the bit in the ROM byte rom_byte_number + # with mask rom_byte_mask + if ( $search_direction == 1){ + $context->{ROM_ID}->[$rom_byte_number] |= $rom_byte_mask; + } else { + $context->{ROM_ID}->[$rom_byte_number] &= ~$rom_byte_mask; + } + # serial number search direction write bit + $serial->bit($search_direction); + # increment the byte counter id_bit_number + # and shift the mask rom_byte_mask + $id_bit_number++; + $rom_byte_mask <<= 1; + #-- if the mask is 0 then go to new rom_byte_number and + if ($rom_byte_mask == 256){ + $rom_byte_number++; + $rom_byte_mask = 1; + } + $context->{LastDiscrepancy} = $last_zero; + main::Log3 ($serial->{name},5,"id_bit_number: $id_bit_number, search_direction: $search_direction, LastDiscrepancy: $serial->{LastDiscrepancy} ROM_ID: ".sprintf("%02X.%02X%02X%02X%02X%02X%02X.%02X",@{$context->{ROM_ID}})); + } + PT_END; + }); +} + +1; \ No newline at end of file diff --git a/fhem/FHEM/OWX_SER.pm b/fhem/FHEM/OWX_SER.pm index 975690ef0..b88473345 100644 --- a/fhem/FHEM/OWX_SER.pm +++ b/fhem/FHEM/OWX_SER.pm @@ -46,17 +46,11 @@ sub new() { my $class = shift; my $self = { interface => "serial", - #-- 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], - #-- search state for 1-Wire bus search - LastDiscrepancy => 0, - LastFamilyDiscrepancy => 0, - LastDeviceFlag => 0, #-- module version - version => 4.1, + version => 5.0, alarmdevs => [], devs => [], + fams => [], timeout => 1.0, #default timeout 1 sec. }; return bless $self,$class; @@ -137,106 +131,21 @@ sub Define ($$) { sub get_pt_alarms() { my ($self) = @_; + my $pt_next; return PT_THREAD(sub { my ($thread) = @_; PT_BEGIN($thread); $self->{alarmdevs} = []; #-- Discover all alarmed devices on the 1-Wire bus - $self->first("alarm"); + $self->first($thread); do { - $self->next("alarm"); - PT_WAIT_UNTIL($self->response_ready()); - PT_EXIT unless $self->next_response("alarm"); - } while( $self->{LastDeviceFlag}==0 ); - main::Log3($self->{name},5, " Alarms = ".join(' ',@{$self->{alarmdevs}})); - PT_EXIT($self->{alarmdevs}); - 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, $dev, $writedata, $numread) = @_; - return PT_THREAD(sub { - my ($thread) = @_; - - PT_BEGIN($thread); - $thread->{writedata} = $writedata; - - $self->reset() if ($reset); - - if (defined $writedata or $numread) { - - my $select; - - #-- has match ROM part - if( $dev ) { - - #-- ID of the device - my $owx_rnf = substr($dev,3,12); - my $owx_f = substr($dev,0,2); - - #-- 8 byte 1-Wire device address - my @rom_id =(0,0,0,0 ,0,0,0,0); - #-- from search string to byte id - $dev=~s/\.//g; - for(my $i=0;$i<8;$i++){ - $rom_id[$i]=hex(substr($dev,2*$i,2)); - } - $select=sprintf("\x55%c%c%c%c%c%c%c%c",@rom_id); - #-- has no match ROM part, issue skip ROM command (0xCC:) - } else { - $select="\xCC"; - } - if (defined $writedata) { - $select.=$writedata; - } - #-- has receive data part - if( $numread ) { - #$numread += length($data); - for( my $i=0;$i<$numread;$i++){ - $select .= "\xFF"; - }; - } - - #-- for debugging - if( $main::owx_async_debug > 1){ - main::Log3($self->{name},5,"OWX_SER::Execute: Sending out ".unpack ("H*",$select)); - } - $self->block($select); - } - - PT_WAIT_UNTIL($self->response_ready()); - - if ($reset and !$self->reset_response()) { - PT_EXIT - } - - my $res = $self->{string_in}; - #-- for debugging - if( $main::owx_async_debug > 1){ - main::Log3($self->{name},5,"OWX_SER::Execute: Receiving ".unpack ("H*",$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_next = $self->pt_next($thread,"alarms"); + PT_WAIT_THREAD($pt_next); + die $pt_next->PT_CAUSE() if ($pt_next->PT_STATE() == PT_ERROR || $pt_next->PT_STATE() == PT_CANCELED); + $self->next_response($thread,"alarms"); + } while( $thread->{LastDeviceFlag}==0 ); + main::Log3($self->{name},5, " Alarms = ".join(' ',@{$thread->{alarmdevs}})); + PT_EXIT($thread->{alarmdevs}); PT_END; }); } @@ -253,17 +162,19 @@ sub get_pt_execute($$$$) { sub get_pt_discover() { my ($self) = @_; + my $pt_next; return PT_THREAD(sub { my ($thread) = @_; PT_BEGIN($thread); #-- Discover all alarmed devices on the 1-Wire bus - $self->first("discover"); + $self->first($thread); do { - $self->next("discover"); - PT_WAIT_UNTIL($self->response_ready()); - PT_EXIT unless $self->next_response("discover"); + $pt_next = $self->pt_next($thread,"discover"); + PT_WAIT_THREAD($pt_next); + die $pt_next->PT_CAUSE() if ($pt_next->PT_STATE() == PT_ERROR || $pt_next->PT_STATE() == PT_CANCELED); + $self->next_response($thread,"discover"); } while( $self->{LastDeviceFlag}==0 ); - PT_EXIT($self->{devs}); + PT_EXIT($thread->{devs}); PT_END; }); } @@ -404,6 +315,7 @@ sub exit($) { sub get_pt_verify($) { my ($self,$dev) = @_; + my $pt_next; return PT_THREAD(sub { my ($thread) = @_; my $i; @@ -412,22 +324,21 @@ sub get_pt_verify($) { my $devs=$dev; $devs=~s/\.//g; for($i=0;$i<8;$i++){ - @{$self->{ROM_ID}}[$i]=hex(substr($devs,2*$i,2)); + $thread->{ROM_ID}->[$i]=hex(substr($devs,2*$i,2)); } #-- reset the search state - $self->{LastDiscrepancy} = 64; - $self->{LastDeviceFlag} = 0; + $thread->{LastDiscrepancy} = 64; + $thread->{LastDeviceFlag} = 0; - $self->reset(); #-- now do the search - $self->next("verify"); - PT_WAIT_UNTIL($self->response_ready()); - PT_EXIT unless $self->next_response("verify"); - - my $dev2=sprintf("%02X.%02X%02X%02X%02X%02X%02X.%02X",@{$self->{ROM_ID}}); + $pt_next = $self->pt_next($thread,"verify"); + PT_WAIT_THREAD($pt_next); + die $pt_next->PT_CAUSE() if ($pt_next->PT_STATE() == PT_ERROR || $pt_next->PT_STATE() == PT_CANCELED); + $self->next_response($thread,"verify"); + my $dev2=sprintf("%02X.%02X%02X%02X%02X%02X%02X.%02X",@{$thread->{ROM_ID}}); #-- reset the search state - $self->{LastDiscrepancy} = 0; - $self->{LastDeviceFlag} = 0; + $thread->{LastDiscrepancy} = 0; + $thread->{LastDeviceFlag} = 0; #-- check result if ($dev eq $dev2){ PT_EXIT(1); @@ -438,10 +349,6 @@ sub get_pt_verify($) { }); }; -####################################################################################### -# -# Private methods -# ####################################################################################### # # First - Find the 'first' devices on the 1-Wire bus @@ -454,57 +361,26 @@ sub get_pt_verify($) { ######################################################################################## sub first($) { - my ($self) = @_; - - #-- clear 16 byte of search data - @{$self->{search}} = (0,0,0,0 ,0,0,0,0, 0,0,0,0, 0,0,0,0); + my ($self,$thread) = @_; #-- reset the search state - $self->{LastDiscrepancy} = 0; - $self->{LastDeviceFlag} = 0; - $self->{LastFamilyDiscrepancy} = 0; -} - -####################################################################################### -# -# Search - Perform the 1-Wire Search Algorithm on the 1-Wire bus using the existing -# search state. -# -# Parameter hash = hash of bus master, mode=alarm,discover or verify -# -# Return 1 : device found, ROM number in owx_ROM_ID and pushed to list (LastDeviceFlag=0) -# or only in owx_ROM_ID (LastDeviceFlag=1) -# 0 : device not found, or ot searched at all -# -######################################################################################## - -sub next($) { - my ($self,$mode)=@_; - - #-- if the last call was the last one, no search - return undef if ( $self->{LastDeviceFlag} == 1 ); - - #-- now do the search - $self->search($mode); + $thread->{LastDiscrepancy} = 0; + $thread->{LastDeviceFlag} = 0; + $thread->{LastFamilyDiscrepancy} = 0; } sub next_response($) { - my ($self,$mode) = @_; - - #TODO find out where contents of @owx_fams come from: - my @owx_fams=(); - - return undef unless $self->search_response(); + my ($self,$thread,$mode) = @_; #-- character version of device ROM_ID, first byte = family - my $dev=sprintf("%02X.%02X%02X%02X%02X%02X%02X.%02X",@{$self->{ROM_ID}}); + my $dev=sprintf("%02X.%02X%02X%02X%02X%02X%02X.%02X",@{$thread->{ROM_ID}}); #--check if we really found a device - if( main::OWX_CRC($self->{ROM_ID})!= 0){ + if( main::OWX_CRC($thread->{ROM_ID})!= 0){ #-- reset the search main::Log3($self->{name},1, "OWX_SER::Search CRC failed : $dev"); - $self->{LastDiscrepancy} = 0; - $self->{LastDeviceFlag} = 0; - $self->{LastFamilyDiscrepancy} = 0; + $thread->{LastDiscrepancy} = 0; + $thread->{LastDeviceFlag} = 0; + $thread->{LastFamilyDiscrepancy} = 0; die "OWX_SER::Search CRC failed : $dev"; } @@ -513,8 +389,8 @@ sub next_response($) { # $self->{LastDeviceFlag}=1; #} #-- - if( $self->{LastDiscrepancy}==$self->{LastFamilyDiscrepancy} ){ - $self->{LastFamilyDiscrepancy}=0; + if( $thread->{LastDiscrepancy}==$thread->{LastFamilyDiscrepancy} ){ + $thread->{LastFamilyDiscrepancy}=0; } #-- mode was to verify presence of a device @@ -524,38 +400,38 @@ sub next_response($) { } elsif( $mode eq "discover" ) { #-- check families my $famfnd=0; - foreach (@owx_fams){ - if( substr($dev,0,2) eq $_ ){ + foreach (@{$self->{fams}}){ + if( substr($dev,0,2) eq $_ ){ #-- if present, set the fam found flag $famfnd=1; last; } } - push(@owx_fams,substr($dev,0,2)) if( !$famfnd ); - foreach (@{$self->{devs}}){ + push(@{$self->{fams}},substr($dev,0,2)) if( !$famfnd ); + foreach (@{$thread->{devs}}){ if( $dev eq $_ ){ #-- if present, set the last device found flag - $self->{LastDeviceFlag}=1; + $thread->{LastDeviceFlag}=1; last; } } - if( $self->{LastDeviceFlag}!=1 ){ + if( $thread->{LastDeviceFlag}!=1 ){ #-- push to list - push(@{$self->{devs}},$dev); + push(@{$thread->{devs}},$dev); main::Log3($self->{name},5, "OWX_SER::Search: new device found $dev"); } #-- mode was to discover alarm devices } else { - for(my $i=0;$i<@{$self->{alarmdevs}};$i++){ - if( $dev eq ${$self->{alarmdevs}}[$i] ){ + for(my $i=0;$i<@{$thread->{alarmdevs}};$i++){ + if( $dev eq ${$thread->{alarmdevs}}[$i] ){ #-- if present, set the last device found flag - $self->{LastDeviceFlag}=1; + $thread->{LastDeviceFlag}=1; last; } } - if( $self->{LastDeviceFlag}!=1 ){ + if( $thread->{LastDeviceFlag}!=1 ){ #--push to list - push(@{$self->{alarmdevs}},$dev); + push(@{$thread->{alarmdevs}},$dev); main::Log3($self->{name},5, "OWX_SER::Search: new alarm device found $dev"); } }