2
0
mirror of https://github.com/fhem/fhem-mirror.git synced 2025-04-17 11:26:03 +00:00

OWX_DS9097: refactoring for new protothreads interface

git-svn-id: https://svn.fhem.de/fhem/trunk@6360 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
ntruchsess 2014-08-04 21:08:10 +00:00
parent 84fec93659
commit eeb8ca0725
3 changed files with 507 additions and 359 deletions

View File

@ -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;

287
fhem/FHEM/OWX_DS9097.pm Normal file
View File

@ -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;

View File

@ -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");
}
}