| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322 |
- ########################################################################################
- #
- # OWX_DS2480.pm
- #
- # FHEM module providing hardware dependent functions for the DS9097 interface of OWX
- #
- # Prof. Dr. Peter A. Henning
- # Norbert Truchsess
- #
- # $Id: OWX_DS9097.pm 10611 2016-01-24 11:15:07Z ntruchsess $
- #
- ########################################################################################
- #
- # 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;
- main::Log3($serial->{name},5, "OWX_DS9097 9600 baud") if ( $main::owx_async_debug > 2 );
- $hwdevice->write("\xF0");
- main::Log3($serial->{name},5, "OWX_DS9097 reset") if ( $main::owx_async_debug > 1 );
- while ($serial->poll()) {};
- $hwdevice->baudrate(115200);
- $hwdevice->write_settings;
- main::Log3($serial->{name},5, "OWX_DS9097 115200 baud") if ( $main::owx_async_debug > 2 );
- }
- }
- sub block($) {
- my ( $serial, $block ) = @_;
- 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);
- }
- }
- 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 $numbits = @bitsout;
- my $bitsin = "";
- my $bit;
- return PT_THREAD(sub {
- my ( $thread ) = @_;
- PT_BEGIN($thread);
- main::Log3($serial->{name},5, "OWX_DS9097 pt_query out: ".$query) if( $main::owx_async_debug );
- while ($serial->poll()) {};
- $serial->{string_raw} = "";
- while (defined ($bit = shift @bitsout)) {
- $serial->bit($bit);
- };
- main::OWX_ASYNC_TaskTimeout($serial->{hash},gettimeofday+main::AttrVal($serial->{name},"timeout",1));
- PT_WAIT_UNTIL(length($serial->{string_raw}) >= $numbits);
- $bitsin = join "", map { ($_ == 0xFF) ? "1" : "0" } unpack "C*",$serial->{string_raw};
- main::Log3($serial->{name},5,"OWX_DS9097 pt_query in: ".$bitsin) if ( $main::owx_async_debug );
- 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 );
- return 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 pt_next ($$) {
- my ($serial,$context,$mode)=@_;
- my $id_bit_number = 1;
- my ($pt_query,$search_direction,@search,$query,$result);
- 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");
- }
- #-- Response search data parsing operates bitwise
- @search = split //, unpack "b64", pack "C8",@{$context->{ROM_ID}};
- #-- bits < LastDiscrepancy are allready known:
- $query = "";
- $result = "";
- if ($context->{LastDiscrepancy} > 0) {
- while ( $id_bit_number < $context->{LastDiscrepancy} ) {
- $query.= "11".$search[$id_bit_number-1];
- $id_bit_number++;
- }
- # $id_bit_number now is equal LastDiscrepancy
- if ($id_bit_number < 65) {
- $query.="111";
- $search[$id_bit_number-1] = 1;
- $id_bit_number++;
- }
- }
- $query.="11" if ($id_bit_number != 57 and $id_bit_number < 65);
- $pt_query = $serial->pt_query($query);
- while (1) {
- 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();
- die "unparsable return of query '$ret'" unless ($ret =~ /(1|0)(1|0)$/);
- $result.=$ret;
- last if ( $id_bit_number > 64 );
- if ( $id_bit_number < 65 ) {
- my $id_bit = $1;
- my $cmp_id_bit = $2;
- 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 {
- $search_direction = 0;
- }
- # set or clear the bit in the ROM byte rom_byte_number
- # with mask rom_byte_mask
- $search[$id_bit_number-1] = $search_direction;
- # serial number search direction write bit
- $serial->bit($search_direction);
- $result.="$search_direction";
- main::Log3 ($serial->{name},5,"id_bit_number: $id_bit_number, search_direction: $search_direction, ROM_ID: ".sprintf("%02X.%02X%02X%02X%02X%02X%02X.%02X",unpack "C8",pack "b64", join "",@search)) if ($main::owx_async_debug);
- $id_bit_number++;
- last if ($id_bit_number > 64);
- $pt_query = $serial->pt_query("11") unless ( $id_bit_number == 57 );
- }
- #bits 57-64 are CRC and can be calculated from bits 1-56
- if ( $id_bit_number == 57 ) {
- my @crc = (0,unpack("C7", pack ("b64", join ("",@search[0..55]))));
- @search[56..63] = split //,unpack "b8",pack "C1",(main::OWX_CRC(\@crc));
- $query = "";
- while ($id_bit_number < 65) {
- $query.= "11".$search[$id_bit_number-1];
- $id_bit_number++;
- }
- $pt_query = $serial->pt_query($query);
- }
- }
- die "unexpected length of result: ".length($result).", expected: 192" if (length($result)!=192);
- my $bit_number = 0;
- my @bits = split //,$result;
- my $last_zero = 0;
- my @found = (0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0);
- if ($main::owx_async_debug>2) {
- my @results;
- for (my $i=0;$i<64;$i++) {
- push @results,substr($result,$i*3,3);
- }
- main::Log3 ($serial->{name},5,"result: ".join(":",@results));
- main::Log3 ($serial->{name},5,"bits: ".join(",",@bits));
- main::Log3 ($serial->{name},5,"search: ".join(",",@search));
- }
- while(@bits) {
- my $id_bit = shift @bits;
- my $cmp_id_bit = shift @bits;
- shift @bits;
- if ($id_bit == 1 and $cmp_id_bit == 1) {
- last;
- } elsif ($id_bit == 0 and $cmp_id_bit == 0) {
- if ($search[$bit_number] == 0) {
- $last_zero = $bit_number+1;
- }
- $found[$bit_number] = $search[$bit_number];
- } else {
- $found[$bit_number] = $id_bit;
- }
- $bit_number++;
- }
- @{$context->{ROM_ID}} = unpack "C8", pack "b64", join "",@found;
- $context->{LastDiscrepancy} = $last_zero;
- main::Log3 ($serial->{name},5,"bit_number: $bit_number, LastDiscrepancy: $last_zero, ROM_ID: ".sprintf("%02X.%02X%02X%02X%02X%02X%02X.%02X",@{$context->{ROM_ID}})) if ($main::owx_async_debug);
- PT_END;
- });
- }
- 1;
|