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:
parent
84fec93659
commit
eeb8ca0725
@ -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
287
fhem/FHEM/OWX_DS9097.pm
Normal 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;
|
@ -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");
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user