| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899 |
- ########################################################################################
- #
- # OWX_TCP.pm
- #
- # FHEM module providing hardware dependent functions for the
- # TCP/IP-UART interfaces of OWX connected to a DS2480
- #
- # Prof. Dr. Peter A. Henning
- #
- # $Id: 11_OWX_TCP.pm 16362 2018-03-09 17:18:43Z phenning $
- #
- ########################################################################################
- #
- # Provides the following methods for OWX
- #
- # Define
- # Detect
- # Alarms
- # Complex
- # Discover
- # Open
- # Close
- # Reopen
- # Init
- # Read
- # Ready
- # Reset
- # Verify
- # Write
- # Query
- # First
- # Next
- # Search
- # SearchLow
- #
- ########################################################################################
- #
- # $hash->{DeviceName} = <ip-addresse>:port
- # $hash->{INTERFACE} = "DS2480";
- # $hash->{TYPE} = "OWX";
- #
- ########################################################################################
- package OWX_TCP;
- use strict;
- use warnings;
- use DevIo;
- ########################################################################################
- #
- # Constructor
- #
- ########################################################################################
- sub new($) {
- my ($class,$hash) = @_;
-
- return bless {
- #-- OWX device
- hash => $hash,
- #-- module version
- version => "7.08",
- #-- 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,
- }, $class;
- }
- ########################################################################################
- #
- # Define - Implements Define method
- #
- # Parameter def = definition string
- #
- # Return undef if ok, otherwise error message
- #
- ########################################################################################
- sub Define ($) {
- my ($self,$def) = @_;
- my $hash = $self->{hash};
-
- my @a = split("[ \t][ \t]*", $def);
- my $dev = $a[2];
-
- my @tcp = split(':',$dev);
- my $ip = $tcp[0];
- my $port= ( $tcp[1] )?$tcp[1]:23;
-
- #-- store with OWX device
- $hash->{DeviceName} = $ip.":".$port;
- $hash->{ASYNCHRONOUS} = 0;
-
- main::Log3 $hash->{NAME},1,"OWX_TCP::Define warning: version ".$hash->{version}." not identical to OWX version "..$main::owx_version
- if( $hash->{version} ne $main::owx_version );
-
- #-- call low level init function for the device
- $self->Init();
- return undef;
- }
- ########################################################################################
- #
- # Detect - Find out if we have the proper interface
- #
- # Return 1 if ok, otherwise 0
- #
- ########################################################################################
- sub Detect () {
- my ($self) = @_;
- my $hash = $self->{hash};
-
- my ($i,$j,$k,$l,$res,$ret,$ress);
- my $name = $hash->{NAME};
- my $ress0 = "OWX_TCP::Detect 1-Wire bus $name: interface ";
- $ress = $ress0;
- my $interface;
-
- #-- timing byte for DS2480
- $self->Query("\xC1",1);
-
- #-- Max 4 tries to detect an interface
- for($l=0;$l<4;$l++) {
- #-- write 1-Wire bus (Fig. 2 of Maxim AN192)
- $res = $self->Query("\x17\x45\x5B\x0F\x91",5);
-
- #-- process 4/5-byte string for detection
- if( !defined($res)){
- $res="";
- $ret=0;
- }elsif( ($res eq "\x16\x44\x5A\x00") || ($res eq "\x16\x44\x5A\x00\x90") || ($res eq "\x16\x44\x5A\x00\x93")){
- $ress .= "master DS2480 detected for the first time";
- $interface="DS2480";
- $ret=1;
- } elsif( ($res eq "\x17\x45\x5B\x0F\x91") || ($res eq "\x17\x45\x1B\x0F\x91")){
- $ress .= "master DS2480 re-detected";
- $interface="DS2480";
- $ret=1;
- } else {
- $ret=0;
- }
- last
- if( $ret==1 );
- main::OWX_WDBGL($name,1,$ress."not found, answer was ",$res);
- $ress = $ress0;
- }
- if( $ret == 0 ){
- $interface=undef;
- main::OWX_WDBGL($name,1,$ress."not detected, answer was ",$res);
- } else {
- main::OWX_WDBGL($name,1,$ress,undef);
- }
- $hash->{INTERFACE} = $interface;
- return $ret;
- }
- ########################################################################################
- #
- # Alarms - Find devices on the 1-Wire bus, which have the alarm flag set
- #
- # Return number of alarmed devices
- #
- ########################################################################################
- sub Alarms () {
- my ($self) = @_;
- my $hash = $self->{hash};
- my $name = $hash->{NAME};
-
- #-- Discover all alarmed devices on the 1-Wire bus
- #main::Log3 $name, 1, "We ARE ASKING FOR ALARMS - WHY NOT ASK THE LAST RESET THING ? ";
- my $res = $self->First("alarm");
- while( $self->{LastDeviceFlag}==0 && $res != 0){
- $res = $res & $self->SER_Next("alarm");
- }
- if( $hash->{ALARMDEVS} ) {
- main::Log3 $name, 1, " Alarms = ".join(' ',@{$hash->{ALARMDEVS}});
- return( int(@{$hash->{ALARMDEVS}}) );
- } else {
- return 0;
- }
- }
- ########################################################################################
- #
- # 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 Complex ($$$$) {
- my ($self,$dev,$data,$numread) =@_;
- my $hash = $self->{hash};
- my $name = $hash->{NAME};
-
- my $select;
- my $res;
-
- #-- 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).$data;
- #-- has no match ROM part
- } else {
- $select=$data;
- }
- #-- has receive data part
- if( $numread >0 ){
- #$numread += length($data);
- for( my $i=0;$i<$numread;$i++){
- $select .= "\xFF";
- };
- }
- main::OWX_WDBGL($name,5,"OWX_TCP::Complex sending ",$select);
-
- #-- send data block (Fig. 6 of Maxim AN192)
- my $data2="";
- my $retlen = length($select);
-
- #-- if necessary, prepend E1 character for data mode
- if( substr($select,0,1) ne '\xE1') {
- $data2 = "\xE1";
- }
- #-- all E3 characters have to be duplicated
- for(my $i=0;$i<length($select);$i++){
- my $newchar = substr($select,$i,1);
- $data2=$data2.$newchar;
- if( $newchar eq '\xE3'){
- $data2=$data2.$newchar;
- }
- }
- #-- write 1-Wire bus as a single string
- $res =$self->Query($data2,$retlen);
- main::OWX_WDBGL($name,5,"OWX_TCP::Complex receiving ",$res);
- return $res
- }
- ########################################################################################
- #
- # Discover - Find devices on the 1-Wire bus
- #
- # Return 1, if alarmed devices found, 0 otherwise.
- #
- ########################################################################################
- sub Discover () {
- my ($self) = @_;
- my $hash = $self->{hash};
-
- #-- zero the array
- @{$hash->{DEVS}}=();
- #-- Discover all devices on the 1-Wire bus
- my $res = $self->First("discover");
- while( $self->{LastDeviceFlag}==0 && $res!=0 ){
- $res = $res & $self->Next("discover");
- }
- return( @{$hash->{DEVS}} == 0);
- }
- ########################################################################################
- #
- # Open - Open Device
- #
- ########################################################################################
- sub Open () {
- my ($self) = @_;
- my $hash = $self->{hash};
-
- return main::DevIo_OpenDev($hash,0,undef);
- }
- ########################################################################################
- #
- # Close - Close Device
- #
- ########################################################################################
- sub Close () {
- my ($self) = @_;
- my $hash = $self->{hash};
-
- return main::DevIo_CloseDev($hash);
- }
- ########################################################################################
- #
- # Reopen - Reopen Device
- #
- ########################################################################################
- sub Reopen () {
- my ($self) = @_;
- my $hash = $self->{hash};
-
- main::DevIo_CloseDev($hash);
- return main::DevIo_OpenDev($hash,0,undef);
- }
- ########################################################################################
- #
- # Init - Implement the Init function. Only reopens the device
- #
- # Return undef if ok
- #
- ########################################################################################
- sub Init() {
- my ($self) = @_;
- my $hash = $self->{hash};
- my $dev = $hash->{DeviceName};
- my $name = $hash->{NAME};
-
- main::Log3 $name, 5,"OWX_TCP::Init called on device $dev for bus $name, state is ".$hash->{STATE};
- main::DevIo_OpenDev($hash,0,undef);
- return undef;
- }
- #######################################################################################
- #
- # Read - Implement the Read function
- #
- # Parameter numexp = expected number of bytes
- #
- #######################################################################################
- sub Read(@) {
- my ($self,$numexp) = @_;
- my $hash = $self->{hash};
- my $name = $hash->{NAME};
- my $buffer = "";
-
- #-- first try to read things
- $buffer = main::DevIo_SimpleRead($hash);
- return $buffer;
-
- }
- ########################################################################################
- #
- # Ready - Implement the Ready function
- #
- # Return 1 : OK
- # 0 : not OK
- #
- ########################################################################################
- sub Ready () {
- my ($self) = @_;
- my $hash = $self->{hash};
- my $name = $hash->{NAME};
- my $success= 0;
-
- main::Log3 $name,5,"OWX_TCP: Ready function called for bus $name. STATE=".$hash->{STATE};
- if($hash->{STATE} eq "disconnected"){
- $success = main::DevIo_OpenDev($hash,1,"main::OWX_Init");
- #main::Log3 $name,5," ===============> success = $success";
- if( !$success ){
- main::DevIo_CloseDev($hash);
- $success = main::DevIo_OpenDev($hash,1,"main::OWX_Init");
- #main::Log3 $name,5," 2nd try ===============> success = $success";
- }
- }
- return $success;
- }
- ########################################################################################
- #
- # Reset - Reset the 1-Wire bus (Fig. 4 of Maxim AN192)
- #
- # Return 1 : OK
- # 0 : not OK
- #
- ########################################################################################
- sub Reset () {
- my ($self)=@_;
- my $hash = $self->{hash};
- my $name = $hash->{NAME};
- my $interface = $hash->{TYPE};
- my $asynchronous = $hash->{ASYNCHRONOUS};
-
- return 0
- if( $hash->{STATE} eq "disconnected" );
-
- my ($res,$r1,$r2);
- #-- Reset command
- my $cmd = "\xE3\xC5";
-
- #-- OWX interface
- if( $interface eq "OWX" ){
- $res = $self->Query($cmd,1);
- $res = "" if( !$res );
- #-- OWX_ASYNC
- }elsif( $interface eq "OWX_ASYNC"){
- $res = $self->Query($cmd,1);
- $res = "" if( !$res );
- }
- #-- process result
- $r1 = ord(substr($res,0,1)) & 192;
- if( $r1 != 192){
- main::OWX_WDBGL($name,4,"OWX_TCP::Reset_TCP failure on bus $name ",$res);
- return 0;
- }
- $hash->{ALARMED} = "no";
-
- $r2 = ord(substr($res,0,1)) & 3;
-
- if( $r2 == 3 ){
- main::Log3($name,4, "OWX_TCP: No presence detected on bus $name");
- return 1;
- }elsif( $r2 ==2 ){
- main::Log3($name,1, "OWX_TCP: Reset_TCP Alarm presence detected on bus $name");
- $hash->{ALARMED} = "yes";
- }
- return 1;
- }
- ########################################################################################
- #
- # Query - Sychronously write to and read from the 1-Wire bus
- #
- # Parameter: cmd = string to send to the 1-Wire bus
- #
- # Return: string received from the 1-Wire bus
- #
- ########################################################################################
- sub Query ($$) {
- my ($self,$cmd,$numexp) = @_;
- my $hash = $self->{hash};
- my $name = $hash->{NAME};
- my $state = $hash->{STATE};
- my $timeout = $hash->{timeout};
- my $timedout = 0;
- my $try = 0;
- my $buffer = "";
- my $numget = 0;
- my $numgeto = 0;
-
- if($state ne "opened") {
- main::Log3 $name, 1, "OWX_TCP::Query attempted to write to $state device $name";
- return undef;
- }
-
- #-- write operation
- main::OWX_WDBGL($name,5,"OWX_TCP::Query $name: Sending out",$cmd);
- return undef unless defined(main::DevIo_SimpleWrite($hash, $cmd, 0));
-
- #-- sleeping for some time
- select(undef,undef,undef,0.04);
-
- #-- first try to read things
- eval {
- local $SIG{ALRM} = sub { die "alarm\n" };
- alarm 1;
- $buffer = main::DevIo_DoSimpleRead($hash);
- alarm 0;
- };
- if ($@) {
- if( $numexp<=1 ){
- main::Log3 $name, 4, "OWX_TCP::Query timed out in first attempt - maybe one byte missing";
- return "";
- }
- main::Log3 $name, 4, "OWX_TCP::Query timed out in first attempt";
- $timedout = 1;
- }
-
- $numget = (defined($buffer))?length($buffer):0;
- $numgeto = $numget;
-
- #-- first try ok
- if( $numget >= $numexp){
- main::Log3 $name, 5, "OWX_TCP::Query $name: Received $numget of $numexp bytes in first attempt and state $state";
- return $buffer;
- #-- several tries to read from slow device
- }elsif( $numget<$numexp ){
- for($try=0;$try<3;$try++) {
- eval {
- local $SIG{ALRM} = sub { die "alarm\n" };
- alarm $timeout;
- $buffer .= main::DevIo_DoSimpleRead($hash);
- alarm 0;
- };
- if ($@) {
- main::Log3 $name, 4, "OWX_TCP::Query timed out in loop attempt no. $try";
- }
- $numget = length($buffer);
- last
- if( $numget>=$numexp );
- select(undef,undef,undef,0.01);
- }
- main::Log3 $name, 5, "OWX_TCP::Query $name: $numget of $numexp bytes in loop $try and state $state"
- if( $numget < $numexp );
- return $buffer
- if( $numget >= $numexp);
- }
-
- #-- something wrong with the 1-Wire device
- if( ($numget == $numgeto) && ($timedout==0) ){
- main::Log3 $name, 1,"OWX_TCP::Query $name: $numget of $numexp bytes - something wrong with the 1-Wire device ???";
- return $buffer;
- #-- ultimate failure
- }else{
- main::OWX_WDBGL($name,5,"OWX_TCP::Query $name: $numget of $numexp bytes in last attempt and state $state. ",$buffer);
- main::DevIo_Disconnected($hash);
- main::InternalTimer(main::gettimeofday()+$timeout, "main::OWX_Ready", $hash,0);
- return $buffer;
- }
- }
- ########################################################################################
- #
- # Verify - Verify a particular device on the 1-Wire bus
- #
- # Parameter dev = 8 Byte ROM ID of device to be tested
- #
- # Return 1 : device found
- # 0 : device not
- #
- ########################################################################################
- sub Verify ($) {
- my ($self,$dev) = @_;
- my $hash = $self->{hash};
- my @rom_id;
- my $i;
-
- #-- from search string to byte id
- my $devs=$dev;
- $devs=~s/\.//g;
- for($i=0;$i<8;$i++){
- $rom_id[$i]=hex(substr($devs,2*$i,2));
- }
- @{$self->{ROM_ID}}=@rom_id;
- #-- reset the search state
- $self->{LastDiscrepancy} = 64;
- $self->{LastDeviceFlag} = 0;
- #-- now do the search
- my $res=$self->Search("verify");
- my $dev2=sprintf("%02X.%02X%02X%02X%02X%02X%02X.%02X",@{$self->{ROM_ID}});
- #-- reset the search state
- $self->{LastDiscrepancy} = 0;
- $self->{LastDeviceFlag} = 0;
- #-- check result
- if ($dev eq $dev2){
- return 1;
- }else{
- return 0;
- }
- }
- #######################################################################################
- #
- # Write - Implement the write function
- #
- #
- # Parameter cmd = string to be sent
- # reset = 1 if initial bus reset has to be done
- #
- ########################################################################################
- sub Write(@) {
- my ($self,$cmd, $reset) = @_;
- my $hash = $self->{hash};
- my $name = $hash->{NAME};
-
- if($hash->{STATE} eq "disconnected"){
- main::Log3 $name,1,"OWX_TCP::Write attempted to disconnected device $name";
- return undef;
- }
-
- #-- if necessary, perform a reset operation
- $self->Reset()
- if( $reset );
-
- #-- if necessary, prepend E1 character for data mode of DS2480
- my $cmd2 = ( substr($cmd,0,1) ne '\xE1')?"\xE1":"";
-
- #-- all E3 characters have to be duplicated in DS2480
- for(my $i=0;$i<length($cmd);$i++){
- my $newchar = substr($cmd,$i,1);
- $cmd2=$cmd2.$newchar;
- if( $newchar eq '\xE3'){
- $cmd2=$cmd2.$newchar;
- }
- }
-
- main::OWX_WDBGL($name,5,"OWX_TCP::Write Sending out ",$cmd2);
-
- main::DevIo_SimpleWrite($hash, $cmd2, 0);
- return;
- }
-
- #######################################################################################
- #
- # First - Find the 'first' devices on the 1-Wire bus
- #
- # Parameter mode
- #
- # Return 1 : device found, ROM number pushed to list
- # 0 : no device present
- #
- ########################################################################################
- sub First ($) {
- my ($self,$mode) = @_;
-
- #-- clear 16 byte of search data
- @{$self->{search}} = (0,0,0,0 ,0,0,0,0, 0,0,0,0, 0,0,0,0);
- #-- reset the search state
- $self->{LastDiscrepancy} = 0;
- $self->{LastDeviceFlag} = 0;
- $self->{LastFamilyDiscrepancy} = 0;
- #-- now do the search
- return $self->Search($mode);
- }
- ########################################################################################
- #
- # Next - Find the 'next' devices on the 1-Wire bus
- #
- # Parameter hash = hash of bus master, mode
- #
- # 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) = @_;
- return $self->Search($mode);
- }
- #######################################################################################
- #
- # Search - Perform the 1-Wire Search Algorithm on the 1-Wire bus using the existing
- # search state.
- #
- # Parameter 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 Search ($) {
- my ($self,$mode)=@_;
- my $hash = $self->{hash};
- my $name = $hash->{NAME};
-
- my @owx_fams=();
-
- #TODO: What if undefined ?
-
- #-- if the last call was the last one, no search
- if ($self->{LastDeviceFlag}==1){
- return 0;
- }
- #-- 1-Wire reset
- if ($self->Reset()==0){
- #-- reset the search
- main::Log(1, "OWX_TCP::Search reset failed on bus $name");
- $self->{LastDiscrepancy} = 0;
- $self->{LastDeviceFlag} = 0;
- $self->{LastFamilyDiscrepancy} = 0;
- return 0;
- }
- #-- here we call the device dependent part
- $self->SearchLow($mode);
-
- #--check if we really found a device
- if( main::OWX_CRC($self->{ROM_ID})!= 0){
- #-- reset the search
- main::Log(1, "OWX_TCP::Search CRC failed on bus $name");
- $self->{LastDiscrepancy} = 0;
- $self->{LastDeviceFlag} = 0;
- $self->{LastFamilyDiscrepancy} = 0;
- return 0;
- }
-
- #-- character version of device ROM_ID, first byte = family
- my $dev=sprintf("%02X.%02X%02X%02X%02X%02X%02X.%02X",@{$self->{ROM_ID}});
-
- #-- for some reason this does not work - replaced by another test, see below
- #if( $self->{LastDiscrepancy}==0 ){
- # $self->{LastDeviceFlag}=1;
- #}
- #--
- if( $self->{LastDiscrepancy}==$self->{LastFamilyDiscrepancy} ){
- $self->{LastFamilyDiscrepancy}=0;
- }
-
- #-- mode was to verify presence of a device
- if ($mode eq "verify") {
- main::Log(5, "OWX_TCP::Search: device verified $dev on bus $name");
- return 1;
- #-- mode was to discover devices
- } elsif( $mode eq "discover" ){
- #-- check families
- my $famfnd=0;
- foreach (@owx_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 (@{$hash->{DEVS}}){
- if( $dev eq $_ ){
- #-- if present, set the last device found flag
- $self->{LastDeviceFlag}=1;
- last;
- }
- }
- if( $self->{LastDeviceFlag}!=1 ){
- #-- push to list
- push(@{$hash->{DEVS}},$dev);
- main::Log(5, "OWX_TCP::Search: new device found $dev on bus $name");
- }
- return 1;
-
- #-- mode was to discover alarm devices
- } elsif( $hash->{ALARMDEVS} ) {
- for(my $i=0;$i<@{$hash->{ALARMDEVS}};$i++){
- if( $dev eq ${$hash->{ALARMDEVS}}[$i] ){
- #-- if present, set the last device found flag
- $self->{LastDeviceFlag}=1;
- last;
- }
- }
- if( $self->{LastDeviceFlag}!=1 ){
- #--push to list
- push(@{$hash->{ALARMDEVS}},$dev);
- main::Log(5, "OWX_TCP::Search: new alarm device found $dev on bus $name");
- }
- return 1;
- }
- }
- ########################################################################################
- #
- # SearchLow - Perform the 1-Wire Search Algorithm on the 1-Wire bus using the existing
- # search state.
- #
- # Parameter 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 SearchLow ($) {
- my ($self,$mode)=@_;
- my $hash = $self->{hash};
- my $name = $hash->{NAME};
-
- my ($sp1,$sp2,$response,$search_direction,$id_bit_number);
-
- #-- Response search data parsing operates bytewise
- $id_bit_number = 1;
-
- select(undef,undef,undef,0.05);
-
- #-- clear 16 byte of search data
- @{$self->{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;
- if( $id_bit_number <= $self->{LastDiscrepancy}){
- #-- first use the ROM ID bit to set the search direction
- if( $id_bit_number < $self->{LastDiscrepancy} ) {
- $search_direction = (@{$self->{ROM_ID}}[$newcpos2]>>$newimsk2) & 1;
- #-- at the last discrepancy search into 1 direction anyhow
- } else {
- $search_direction = 1;
- }
- #-- fill into search data;
- @{$self->{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",@{$self->{search}});
- $response = $self->Query($sp1,1);
- $response = $self->Query($sp2,16);
-
- #-- interpret the return data
- if( length($response)!=16 ) {
- main::Log(3, "OWX_TCP::Search_TCP on bus $name 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
- $id_bit_number = 1;
- #-- clear 8 byte of device id for current search
- @{$self->{ROM_ID}} =(0,0,0,0 ,0,0,0,0);
- 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) ){
- $self->{LastDiscrepancy}=$id_bit_number;
- if( $id_bit_number < 9 ){
- $self->{LastFamilyDiscrepancy}=$id_bit_number;
- }
- }
- #-- fill into device data; one char per 8 bits
- @{$self->{ROM_ID}}[int(($id_bit_number-1)/8)]+=$newibit<<(($id_bit_number-1)%8);
-
- #-- increment number
- $id_bit_number++;
- }
- return 1;
- }
- 1;
- =pod
- =item device
- =item summary to address an OWX interface device via TCP/IP
- =item summary_DE zur Adressierung eines OWX Interface Device mit TCP/IP
- =begin html
- <a name="OWX_TCP"></a>
- <h3>OWX_TCP</h3>
- <ul>
- See <a href="/fhem/docs/commandref.html#OWX">OWX</a>
- </ul>
- =end html
- =begin html_DE
- <a name="OWX_TCP"></a>
- <h3>OWX_TCP</h3>
- <ul>
- <a href="http://fhemwiki.de/wiki/Interfaces_f%C3%BCr_1-Wire">Deutsche Dokumentation im Wiki</a> vorhanden, die englische Version gibt es hier: <a href="/fhem/docs/commandref.html#OWX">OWX</a>
- </ul>
- =end html_DE
|