############################################## # $Id$ package main; use strict; use warnings; use Time::HiRes qw(gettimeofday usleep); my @clients = qw( I2C_LCD I2C_DS1307 I2C_PC.* I2C_MCP.* I2C_BM.* I2C_SH.* I2C_TSL.* I2C_SUSV I2C_LM.* I2C_AD.* ); my $gpioprg = "/usr/local/bin/gpio"; #WiringPi GPIO utility my $I2C_SLAVE = 0x0703; #Variable for IOCTL (set I2C slave address) my $libcheck_SMBus = 1; my $check_ioctl_ph = 1; sub RPII2C_Initialize($) { my ($hash) = @_; eval "use Device::SMBus;"; $libcheck_SMBus = 0 if($@); eval {require "sys/ioctl.ph"}; $check_ioctl_ph = 0 if($@); # Provider $hash->{Clients} = join (':',@clients); $hash->{I2CWrtFn} = "RPII2C_Write"; #alternative fuer IOWrite # Normal devices $hash->{DefFn} = "RPII2C_Define"; $hash->{UndefFn} = "RPII2C_Undef"; $hash->{GetFn} = "RPII2C_Get"; $hash->{SetFn} = "RPII2C_Set"; $hash->{AttrFn} = "RPII2C_Attr"; $hash->{NotifyFn} = "RPII2C_Notify"; $hash->{AttrList}= "do_not_notify:1,0 ignore:1,0 showtime:1,0 " . "$readingFnAttributes"; $hash->{AttrList} .= " useHWLib:IOCTL,SMBus " if( $libcheck_SMBus && $check_ioctl_ph); $hash->{AttrList} .= " swap_i2c0:off,on"; } ##################################### sub RPII2C_Define($$) { # my ($hash, $def) = @_; my @a = split("[ \t][ \t]*", $def); unless(@a == 3) { my $msg = "wrong syntax: define RPII2C <0|1>"; Log3 undef, 2, $msg; return $msg; } $hash->{SMBus_exists} = $libcheck_SMBus if($libcheck_SMBus); $hash->{ioctl_ph_exists} = $check_ioctl_ph if($check_ioctl_ph); my $name = $a[0]; my $dev = $a[2]; if ($check_ioctl_ph) { $hash->{hwfn} = \&RPII2C_HWACCESS_ioctl; } elsif ($libcheck_SMBus) { $hash->{hwfn} = \&RPII2C_HWACCESS; } else { return $name . ": Error! no library for Hardware access installed"; } my $device = "/dev/i2c-".$dev; if ( RPII2C_CHECK_I2C_DEVICE($device) ) { Log3 $hash, 3, "$hash->{NAME}: file $device not accessible try to use gpio utility to fix it"; if ( defined(my $ret = RPII2C_CHECK_GPIO_UTIL($gpioprg)) ) { Log3 $hash, 1, "$hash->{NAME}: " . $ret if $ret; } else { #I2C Devices mit gpio utility fuer FHEM User lesbar machen my $exp = $gpioprg.' load i2c'; $exp = `$exp`; } } $hash->{NOTIFYDEV} = "global"; if($dev eq "none") { Log3 $name, 1, "$name device is none, commands will be echoed only"; $attr{$name}{dummy} = 1; return undef; } my $check = RPII2C_CHECK_I2C_DEVICE($device); return $name . $check if $check; $hash->{DeviceName} = $device; $hash->{STATE} = "initialized"; return undef; } ##################################### sub RPII2C_Notify { # my ($hash,$dev) = @_; my $name = $hash->{NAME}; my $type = $hash->{TYPE}; if( grep(m/^(INITIALIZED|REREADCFG)$/, @{$dev->{CHANGED}}) ) { RPII2C_forall_clients($hash,\&RPII2C_Init_Client,undef);; } elsif( grep(m/^SAVE$/, @{$dev->{CHANGED}}) ) { } } ##################################### sub RPII2C_forall_clients($$$) { # my ($hash,$fn,$args) = @_; foreach my $d ( sort keys %main::defs ) { if ( defined( $main::defs{$d} ) && defined( $main::defs{$d}{IODev} ) && $main::defs{$d}{IODev} == $hash ) { &$fn($main::defs{$d},$args); } } return undef; } ##################################### sub RPII2C_Init_Client($@) { # my ($hash,$args) = @_; if (!defined $args and defined $hash->{DEF}) { my @a = split("[ \t][ \t]*", $hash->{DEF}); $args = \@a; } my $name = $hash->{NAME}; Log3 $name,5,"im init client fuer $name "; my $ret = CallFn($name,"InitFn",$hash,$args); if ($ret) { Log3 $name,2,"error initializing '".$hash->{NAME}."': ".$ret; } } ##################################### sub RPII2C_Undef($$) { # my ($hash, $arg) = @_; my $name = $hash->{NAME}; foreach my $d (sort keys %defs) { if(defined($defs{$d}) && defined($defs{$d}{IODev}) && $defs{$d}{IODev} == $hash) { Log3 $name, 3, "deleting port for $d"; delete $defs{$d}{IODev}; } } return undef; } ##################################### sub RPII2C_Attr(@){ my (undef, $name, $attr, $val) = @_; my $hash = $defs{$name}; if ($attr && $attr eq 'useHWLib') { $hash->{hwfn} = \&RPII2C_HWACCESS_ioctl if $val eq "IOCTL"; $hash->{hwfn} = \&RPII2C_HWACCESS if $val eq "SMBus"; } elsif ($attr && $attr eq 'swap_i2c0' && defined($val)) { RPII2C_SWAPI2C0($hash,$val); } return undef; } ##################################### sub RPII2C_Set($@) { # my ($hash, @a) = @_; my $name = shift @a; my $type = shift @a; my @sets = ('writeByte', 'writeByteReg', 'writeBlock', 'writeBlockReg'); #, 'writeNBlock'); return "Unknown argument $type, choose one of " . join(" ", @sets) if @a < 2; foreach (@a) { #Hexwerte pruefen und in Dezimalwerte wandeln return "$name: $_ is no 1byte hexadecimal value" if $_ !~ /^(0x|)[0-9A-F]{1,2}$/xi ; $_ = hex; } my $i2ca = shift @a; return "$name: I2C Address not valid" unless ($i2ca > 3 && $i2ca < 128); #pruefe auf Hexzahl zwischen 4 und 7F my $i2chash = { i2caddress => $i2ca, direction => "i2cbytewrite", test => "local" }; my ($reg, $nbyte, $data) = undef; if ($type eq "writeByte") { $data = join(" ", @a); } elsif ($type eq "writeByteReg") { $reg = shift @a; $data = join(" ", @a); } elsif ($type eq "writeBlock") { $nbyte = int(@a); return "$name maximal blocksize (32byte) exeeded" if $nbyte > 32; $data = join(" ", @a); $i2chash->{direction} = "i2cwrite"; } elsif ($type eq "writeBlockReg") { $reg = shift @a; $nbyte = int(@a); return "$name maximal blocksize (32byte) exeeded" if $nbyte > 32; $data = join(" ", @a); $i2chash->{direction} = "i2cwrite"; } else { return "Unknown argument $type, choose one of " . join(" ", @sets); } $i2chash->{reg} = $reg if defined($reg); #startadresse zum lesen $i2chash->{nbyte} = $nbyte if defined($nbyte); $i2chash->{data} = $data if defined($data); &{$hash->{hwfn}}($hash, $i2chash); undef $i2chash; #Hash loeschen return undef; } ##################################### sub RPII2C_Get($@) { # my ($hash, @a) = @_; my $nargs = int(@a); my $name = $hash->{NAME}; my @gets = ('read','readblock','readblockreg'); unless ( exists($a[1]) && $a[1] ne "?" && grep {/^$a[1]$/} @gets ) { return "Unknown argument $a[1], choose one of " . join(" ", @gets); } if ($a[1] eq "read") { return "use: \"get $name $a[1] [ []]\"" if(@a < 3); return "$name: I2C Address not valid" unless ( $a[2] =~ /^(0x|)([0-7]|)[0-9A-F]$/xi); return "$name register address must be a hexvalue" if (defined($a[3]) && $a[3] !~ /^(0x|)[0-9A-F]{1,4}$/xi); return "$name number of bytes must be decimal value" if (defined($a[4]) && $a[4] !~ /^[0-9]{1,2}$/); my $i2chash = { i2caddress => hex($a[2]), direction => "i2cbyteread" }; $i2chash->{reg} = hex($a[3]) if defined($a[3]); #startadresse zum lesen $i2chash->{nbyte} = $a[4] if defined($a[4]); my $status = &{$hash->{hwfn}}($hash, $i2chash); #als Array my $received = $i2chash->{received}; #als Scalar undef $i2chash; #Hash loeschen return (defined($received) ? "received : " . $received ." | " : "" ) . " transmission: $status"; } elsif ($a[1] eq "readblock") { return "use: \"get $name $a[1] []\"" if(@a < 3); return "$name: I2C Address not valid" unless ( $a[2] =~ /^(0x|)([0-7]|)[0-9A-F]$/xi); return "$name number of bytes must be decimal value" if (defined($a[3]) && $a[3] !~ /^[0-9]{1,2}$/); my $i2chash = { i2caddress => hex($a[2]), direction => "i2cread" }; $i2chash->{nbyte} = $a[3] if defined($a[3]); my $status = &{$hash->{hwfn}}($hash, $i2chash); my $received = $i2chash->{received}; #als Scalar undef $i2chash; #Hash loeschen return (defined($received) ? "received : " . $received ." | " : "" ) . " transmission: $status"; } elsif ($a[1] eq "readblockreg") { return "use: \"get $name $a[1] []\"" if(@a < 2); return "$name: I2C Address not valid" unless ( $a[2] =~ /^(0x|)([0-7]|)[0-9A-F]$/xi); return "$name register address must be a hexvalue" if (defined($a[3]) && $a[3] !~ /^(0x|)[0-9A-F]{1,4}$/xi); return "$name number of bytes must be decimal value" if (defined($a[4]) && $a[4] !~ /^[0-9]{1,2}$/); my $i2chash = { i2caddress => hex($a[2]), direction => "i2cread" }; $i2chash->{reg} = hex($a[3]) if defined($a[3]); $i2chash->{nbyte} = $a[4] if defined($a[4]); my $status = &{$hash->{hwfn}}($hash, $i2chash); my $received = $i2chash->{received}; #als Scalar undef $i2chash; #Hash loeschen return (defined($received) ? "received : " . $received ." | " : "" ) . " transmission: $status"; } return undef; } ##################################### sub RPII2C_Write($$) { #wird vom Client aufgerufen my ($hash, $clientmsg) = @_; my $name = $hash->{NAME}; my $ankommen = "$name: vom client empfangen"; foreach my $av (keys %{$clientmsg}) { $ankommen .= "|" . $av . ": " . $clientmsg->{$av}; } Log3 $hash, 5, $ankommen; if ( $clientmsg->{direction} && $clientmsg->{i2caddress} ) { $clientmsg->{$name . "_" . "SENDSTAT"} = &{$hash->{hwfn}}($hash, $clientmsg); #$clientmsg->{$name . "_" . "SENDSTAT"} = RPII2C_HWACCESS($hash, $clientmsg); } foreach my $d ( sort keys %main::defs ) { #zur Botschaft passenden Clienten ermitteln geht auf Client: I2CRecFn #Log3 $hash, 1, "d: $d". ($main::defs{$d}{IODev}? ", IODev: $main::defs{$d}{IODev}":"") . ($main::defs{$d}{I2C_Address} ? ", I2C: $main::defs{$d}{I2C_Address}":"") . ($clientmsg->{i2caddress} ? " CI2C: $clientmsg->{i2caddress}" : ""); if ( defined( $main::defs{$d} ) && defined( $main::defs{$d}{IODev} ) && $main::defs{$d}{IODev} == $hash && defined( $main::defs{$d}{I2C_Address} ) && defined($clientmsg->{i2caddress}) && $main::defs{$d}{I2C_Address} eq $clientmsg->{i2caddress} ) { my $chash = $main::defs{$d}; Log3 $hash, 5, "$name ->Client gefunden: $d". ($main::defs{$d}{I2C_Address} ? ", I2Caddress: $main::defs{$d}{I2C_Address}":"") . ($clientmsg->{data} ? " Data: $clientmsg->{data}" : "") . ($clientmsg->{received} ? " Gelesen: $clientmsg->{received}" : ""); CallFn($d, "I2CRecFn", $chash, $clientmsg); undef $clientmsg #Hash loeschen nachdem Daten verteilt wurden } } return undef; } sub RPII2C_CHECK_I2C_DEVICE { my ($dev) = @_; my $ret = undef; if(-e $dev) { if(-r $dev) { unless(-w $dev) { $ret = ': Error! I2C device not writable: '.$dev . '. Please install wiringpi or change access rights for fhem user'; } } else { $ret = ': Error! I2C device not readable: '.$dev . '. Please install wiringpi or change access rights for fhem user'; } } else { $ret = ': Error! I2C device not found: ' .$dev . '. Please check kernelmodules must loaded: i2c_bcm2708, i2c_dev'; } return $ret; } sub RPII2C_CHECK_GPIO_UTIL { my ($gpioprg) = @_; my $ret = undef; if(-e $gpioprg) { if(-x $gpioprg) { unless(-u $gpioprg) { $ret = "file $gpioprg is not setuid"; } } else { $ret = "file $gpioprg is not executable"; } } else { $ret = "file $gpioprg doesnt exist"; } return $ret; } sub RPII2C_SWAPI2C0 { my ($hash,$set) = @_; unless (defined(my $ret = RPII2C_CHECK_GPIO_UTIL($gpioprg))) { if (defined($set) && $set eq "on") { system "$gpioprg -g mode 0 in"; system "$gpioprg -g mode 1 in"; system "$gpioprg -g mode 28 ALT0"; system "$gpioprg -g mode 29 ALT0"; } else { system "$gpioprg -g mode 28 in"; system "$gpioprg -g mode 29 in"; system "$gpioprg -g mode 0 ALT0"; system "$gpioprg -g mode 1 ALT0"; } } else { Log3 $hash, 1, $hash->{NAME} . ": " . $ret if $ret; } return } sub RPII2C_HWACCESS($$) { my ($hash, $clientmsg) = @_; my $status = "error"; my $inh = undef; Log3 $hash, 5, "$hash->{NAME}: HWaccess I2CAddr: " . sprintf("0x%.2X", $clientmsg->{i2caddress}); my $dev = Device::SMBus->new( I2CBusDevicePath => $hash->{DeviceName}, I2CDeviceAddress => hex( sprintf("%.2X", $clientmsg->{i2caddress}) ), ); if ( defined($clientmsg->{reg}) && defined($clientmsg->{data}) && $clientmsg->{direction} eq "i2cwrite") { #blockweise beschreiben (Register) my @data = split(" ", $clientmsg->{data}); my $dataref = \@data; $inh = $dev->writeBlockData( $clientmsg->{reg} , $dataref ); my $wr = join(" ", @{$dataref}); Log3 $hash, 5, "$hash->{NAME}: Block schreiben Register: " . sprintf("0x%.2X", $clientmsg->{reg}) . " Inhalt: " . $wr . " N: ". int(@data) ." Returnvar.: $inh"; $status = "Ok" if $inh == 0; } elsif (defined($clientmsg->{reg}) && defined($clientmsg->{data}) && $clientmsg->{direction} eq "i2cbytewrite") { #byteweise beschreiben (Register) my @data = split(" ", $clientmsg->{data}); foreach (@data) { $inh = $dev->writeByteData($clientmsg->{reg},$_); Log3 $hash, 5, "$hash->{NAME}; Register ".sprintf("0x%.2X", $clientmsg->{reg})." schreiben - Inhalt: " .sprintf("0x%.2X",$_) . " Returnvar.: $inh"; last if $inh != 0; $status = "Ok" if $inh == 0; } } elsif (defined($clientmsg->{data}) && ( $clientmsg->{direction} eq "i2cwrite" || $clientmsg->{direction} eq "i2cbytewrite" ) ) { #Byte(s) schreiben my @data = split(" ", $clientmsg->{data}); foreach (@data) { $inh = $dev->writeByte($_); Log3 $hash, 5, "$hash->{NAME} Byte schreiben; Inh: " . $_ . " Returnvar.: $inh"; last if $inh != 0; $status = "Ok" if $inh == 0; } } elsif (defined($clientmsg->{reg}) && ( $clientmsg->{direction} eq "i2cread" || $clientmsg->{direction} eq "i2cbyteread" ) ) { #byteweise lesen (Register) my $nbyte = defined($clientmsg->{nbyte}) ? $clientmsg->{nbyte} : 1; my $rmsg = ""; for (my $n = 0; $n < $nbyte; $n++) { $inh = $dev->readByteData($clientmsg->{reg} + $n ); Log3 $hash, 5, "$hash->{NAME}; Register ".sprintf("0x%.2X", $clientmsg->{reg} + $n )." lesen - Inhalt: ".sprintf("0x%.2X",$inh); last if ($inh < 0); #$rmsg .= sprintf("%.2X",$inh); $rmsg .= $inh; $rmsg .= " " if $n <= $nbyte; $status = "Ok" if ($n + 1) == $nbyte; } #@{$clientmsg->{received}} = split(" ", $rmsg) if($rmsg); #Daten als Array uebertragen $clientmsg->{received} = $rmsg if($rmsg); #Daten als Scalar uebertragen } elsif ($clientmsg->{direction} eq "i2cread"|| $clientmsg->{direction} eq "i2cbyteread") { #Byte lesen my $nbyte = defined($clientmsg->{nbyte}) ? $clientmsg->{nbyte} : 1; my $rmsg = ""; for (my $n = 0; $n < $nbyte; $n++) { $inh = $dev->readByte(); Log3 $hash, 5, "$hash->{NAME} Byte lesen; Returnvar.: $inh"; last if ($inh < 0); $rmsg .= $inh; $rmsg .= " " if $n <= $nbyte; $status = "Ok" if ($n + 1) == $nbyte; } #@{$clientmsg->{received}} = split(" ", $rmsg) if($rmsg); #Daten als Array uebertragen $clientmsg->{received} = $rmsg if($rmsg); #Daten als Scalar uebertragen } $hash->{STATE} = $status; $hash->{ERRORCNT} = defined($hash->{ERRORCNT}) ? $hash->{ERRORCNT} += 1 : 1 if $status ne "Ok"; $clientmsg->{$hash->{NAME} . "_" . "RAWMSG"} = $inh; return $status; } ##################### sub RPII2C_HWACCESS_ioctl($$) { my ($hash, $clientmsg) = @_; my $status = "error"; Log3 $hash, 5, "$hash->{NAME}: HWaccess I2CAddr: " . sprintf("0x%.2X", $clientmsg->{i2caddress}); my ($fh, $msg) = undef; my $ankommen = "$hash->{NAME}: vom client empfangen"; foreach my $av (keys %{$clientmsg}) { $ankommen .= "|" . $av . ": " . $clientmsg->{$av}; } Log3 $hash, 5, $ankommen; my $i2caddr = hex(sprintf "%x", $clientmsg->{i2caddress}); if ( sysopen(my $fh, $hash->{DeviceName}, O_RDWR) != 1) { #Datei oeffnen Log3 $hash, 3, "$hash->{NAME}: HWaccess sysopen failure: $!" } elsif( not defined( ioctl($fh,$I2C_SLAVE,$i2caddr) ) ) { #I2C Adresse per ioctl setzen Log3 $hash, 3, "$hash->{NAME}: HWaccess (0x".unpack( "H2",pack "C", $clientmsg->{i2caddress}).") ioctl failure: $!" } elsif ( defined($clientmsg->{data}) && $clientmsg->{direction} eq "i2cwrite") { #blockweise schreiben my $data = defined($clientmsg->{reg}) ? chr($clientmsg->{reg}) : undef; foreach (split(" ", $clientmsg->{data})) { $data .= chr($_); } my $retval = syswrite($fh, $data, length($data)); unless (defined($retval) && $retval == length($data)) { Log3 $hash, 3, "$hash->{NAME}: HWaccess blockweise nach 0x".unpack( "H2",pack "C", $clientmsg->{i2caddress})." schreiben, " . (defined($clientmsg->{reg}) ? "Reg: 0x". unpack( "H2",pack "C", $clientmsg->{reg}) : "") . " Inh: $clientmsg->{data}, laenge: ".length($data)."| -> syswrite failure: $!"; } else { $status = "Ok"; Log3 $hash, 5, "$hash->{NAME}: HWaccess block schreiben, " . (defined($clientmsg->{reg}) ? "Reg: 0x". unpack( "H2",pack "C", $clientmsg->{reg}) : "") . " Inh(dec):|$clientmsg->{data}|, laenge: |".length($data)."|"; } } elsif (defined($clientmsg->{data}) && $clientmsg->{direction} eq "i2cbytewrite") { #byteweise schreiben my $reg = undef; $reg = $clientmsg->{reg} if (defined($clientmsg->{reg})); $status = "Ok"; foreach (split(" ", $clientmsg->{data})) { my $data = (defined($reg) ? chr($reg++) : "") . chr($_); my $retval = syswrite($fh, $data, length($data)); #Log3 $hash, 1, "retval= $retval" if $clientmsg->{test} eq "local"; unless (defined($retval) && $retval == length($data)) { Log3 $hash, 3, "$hash->{NAME}: HWaccess byteweise nach 0x".unpack( "H2",pack "C", $clientmsg->{i2caddress})." schreiben, ". (defined($reg) ? "Reg: 0x". unpack( "H2",pack "C", ($reg - 1)) . " " : "")."Inh: 0x" . unpack( "H2",pack "C", $_) .", laenge: ".length($data)."| -> syswrite failure: $!"; $status = "error"; last; } Log3 $hash, 5, "$hash->{NAME}: HWaccess byteweise schreiben, ". (defined($reg) ? "Reg: 0x". unpack( "H2",pack "C", ($reg - 1)) . " " : "")."Inh: 0x" . unpack( "H2",pack "C", $_) .", laenge: ".length($data); #Log3 $hash, 1, "$hash->{NAME}: HWaccess byteweise zu 0x".unpack( "H2",pack "C", $clientmsg->{i2caddress})." schreiben, ". (defined($reg) ? "Reg: 0x". unpack( "H2",pack "C", ($reg - 1)) . " " : "")."Inh: 0x" . unpack( "H2",pack "C", $_) .", laenge: ".length($data) if $clientmsg->{test} eq "local"; } } elsif ($clientmsg->{direction} eq "i2cbyteread") { #byteweise lesen my $nbyte = defined($clientmsg->{nbyte}) ? $clientmsg->{nbyte} : 1; my $rmsg = ""; foreach (my $n = 0; $n < $nbyte; $n++) { if ( defined($clientmsg->{reg}) ) { Log3 $hash, 5, "$hash->{NAME}: HWaccess byteweise lesen setze Registerpointer auf " . ($clientmsg->{reg} + $n); my $retval = syswrite($fh, chr($clientmsg->{reg} + $n), 1); unless (defined($retval) && $retval == 1) { Log3 $hash, 3, "$hash->{NAME}: HWaccess byteweise von 0x".unpack( "H2",pack "C", $clientmsg->{i2caddress})." lesen,". (defined($clientmsg->{reg}) ? " Reg: 0x". unpack( "H2",pack "C", ($clientmsg->{reg} + $n)) : "") . " -> syswrite failure: $!" if $!; last; } } if (defined($clientmsg->{usleep})) { usleep($clientmsg->{usleep}); } my $buf = undef; my $retval = sysread($fh, $buf, 1); unless (defined($retval) && $retval == 1) { Log3 $hash, 3, "$hash->{NAME}: HWaccess byteweise von 0x".unpack( "H2",pack "C", $clientmsg->{i2caddress})." lesen,". (defined($clientmsg->{reg}) ? " Reg: 0x". unpack( "H2",pack "C", ($clientmsg->{reg} + $n)) : "") . " -> sysread failure: $!" if $!; last; } $rmsg .= ord($buf); $rmsg .= " " if $n <= $nbyte; $status = "Ok" if ($n + 1) == $nbyte; } $clientmsg->{received} = $rmsg if($rmsg); #Daten als Scalar uebertragen } elsif ($clientmsg->{direction} eq "i2cread") { #blockweise lesen my $nbyte = defined($clientmsg->{nbyte}) ? $clientmsg->{nbyte} : 1; my $rmsg = ""; if ( defined($clientmsg->{reg}) ) { Log3 $hash, 4, "$hash->{NAME}: HWaccess blockweise lesen setze Registerpointer auf " . ($clientmsg->{reg}); my $retval = syswrite($fh, chr($clientmsg->{reg}), 1); unless (defined($retval) && $retval == 1) { Log3 $hash, 3, "$hash->{NAME}: HWaccess blockweise von 0x".unpack( "H2",pack "C", $clientmsg->{i2caddress})." lesen,". (defined($clientmsg->{reg}) ? " Reg: 0x". unpack( "H2",pack "C", ($clientmsg->{reg})) : "") . " -> syswrite failure: $!" if $!; $status = "regerror"; } } unless ($status eq "regerror") { usleep($clientmsg->{usleep}) if defined $clientmsg->{usleep}; my $buf = undef; my $retval = sysread($fh, $buf, $nbyte); unless (defined($retval) && $retval == $nbyte) { Log3 $hash, 3, "$hash->{NAME}: HWaccess blockweise von 0x".unpack( "H2",pack "C", $clientmsg->{i2caddress})." lesen,". (defined($clientmsg->{reg}) ? " Reg: 0x". unpack( "H2",pack "C", ($clientmsg->{reg})) : "") . " -> sysread failure: $!" if $!; } else { $rmsg = $buf; $rmsg =~ s/(.|\n)/sprintf("%u ",ord($1))/eg; #Log3 $hash, 1, "test Blockweise lesen menge: |$nbyte|, inh: |$buf|, ergebnis: |$rmsg|"; $clientmsg->{received} = $rmsg if($rmsg); #Daten als Scalar uebertragen $status = "Ok" } } } $hash->{STATE} = $status; $hash->{ERRORCNT} = defined($hash->{ERRORCNT}) ? $hash->{ERRORCNT} += 1 : 1 if $status ne "Ok"; #$clientmsg->{$hash->{NAME} . "_" . "RAWMSG"} = $inh; return $status; } =pod =item device =item summary accesses I2C interface via sysfs on linux =item summary_DE Zugriff auf das I2C-Interface über sysfs auf Linux Systemen =begin html

RPII2C

    Provides access to Raspberry Pi's I2C interfaces for some logical modules and also directly.
    This modul will basically work on every linux system that provides /dev/i2c-x.

    preliminary:
    • load I2C kernel modules (choose one of the following options):
      • open /etc/modules
          sudo nano /etc/modules

        add these lines
          i2c-dev
          i2c-bcm2708
      • Since Kernel 3.18.x on raspberry pi and maybe on other boards too, device tree support was implemented and enabled by default. To enable I2C support just add
          device_tree_param=i2c0=on,i2c1=on
        to /boot/config.txt You can also enable just one of the I2C. In this case remove the unwantet one from the line.
      • On Raspbian images since 2015 just start sudo raspi-config and enable I2C there. Parameters will be added automaticly to /boot/config.txt
      • reboot

    • Choose only one of the three follwing methodes do grant access to /dev/i2c-* for FHEM user:
      • sudo apt-get install i2c-tools
        sudo adduser fhem i2c
        sudo reboot


      • Add following lines into /etc/init.d/fhem before perl fhem.pl line in start or into /etc/rc.local:
        sudo chown fhem /dev/i2c-*
        sudo chgrp dialout /dev/i2c-*
        sudo chmod +t /dev/i2c-*
        sudo chmod 660 /dev/i2c-*

      • Alternatively for Raspberry Pi you can install the gpio utility from WiringPi library change access rights of I2C-Interface
        WiringPi installation is described here: RPI_GPIO.
        gpio utility will be automaticly used, if installed.
        Important: to use I2C-0 at P5 connector you must use attribute swap_i2c0.

    • Optional: access via IOCTL will be used (RECOMMENDED) if Device::SMBus is not present.
      To access the I2C-Bus via the Device::SMBus module, following steps are necessary:
        sudo apt-get install libmoose-perl
        sudo cpan Device::SMBus

    • For Raspbian users only
      If you are using I2C-0 at P5 connector on Raspberry Pi model B with newer raspbian versions, including support for Raspberry Pi model B+, you must add following line to /boot/cmdline.txt:
        bcm2708.vc_i2c_override=1


    Define
      define <name> RPII2C <I2C Bus Number>
      where <I2C Bus Number> is the number of the I2C bus that should be used (0 or 1)

    Set
    • Write one byte (or more bytes sequentially) directly to an I2C device (for devices that have only one register to write):
      set <name> writeByte <I2C Address> <value>

    • Write n-bytes to an register range (as an series of single register write operations), beginning at the specified register:
      set <name> writeByteReg <I2C Address> <Register Address> <value> [<value> [..]]

    • Write n-bytes directly to an I2C device (as an block write operation):
      set <name> writeBlock <I2C Address> <Register Address> <value> [<value> [..]]

    • Write n-bytes to an register range (as an block write operation), beginning at the specified register:
      set <name> writeBlockReg <I2C Address> <Register Address> <value> [<value> [..]]


    • Examples:
        Write 0xAA to device with I2C address 0x60
        set test1 writeByte 60 AA
        Write 0xAA to register 0x01 of device with I2C address 0x6E
        set test1 writeByteReg 6E 01 AA
        Write 0xAA to register 0x01 of device with I2C address 0x6E, after it write 0x55 to 0x02 as two separate commands
        set test1 writeByteReg 6E 01 AA 55
        Write 0xA4 to register 0x03, 0x00 to register 0x04 and 0xDA to register 0x05 of device with I2C address 0x60 as an block command
        set test1 writeBlock 60 03 A4 00 DA

    Get
    • Gets value of I2C device's registers:
      get <name> read <I2C Address> [<Register Address> [<number of registers>]]

    • Gets value of I2C device in blockwise mode:
      get <name> readblock <I2C Address> [<number of registers>]

    • Gets value of I2C device's registers in blockwise mode:
      get <name> readblockreg <I2C Address> <Register Address> [<number of registers>]


    • Examples:
        Reads byte from device with I2C address 0x60
        get test1 read 60
        Reads register 0x01 of device with I2C address 0x6E.
        get test1 read 6E 01 AA 55
        Reads register 0x03 to 0x06 of device with I2C address 0x60.
        get test1 read 60 03 4


    Attributes
    • swap_i2c0
      Swap Raspberry Pi's I2C-0 from J5 to P5 rev. B
      This attribute is for Raspberry Pi only and needs gpio utility from WiringPi library.
      Default: none, valid values: on, off

    • useHWLib
      Change hardware access method.
      Attribute exists only if both access methods are usable
      Default: IOCTL, valid values: IOCTL, SMBus

    • ignore
    • do_not_notify
    • showtime

=end html =begin html_DE

RPII2C

    Ermöglicht den Zugriff auf die I2C Schnittstellen des Raspberry Pi, BBB, Cubie über logische Module. Register von I2C IC's können auch direkt gelesen und geschrieben werden.

    Dieses Modul funktioniert grunsätzlich auf allen Linux Systemen, die /dev/i2c-x bereitstellen.

    Vorbereitung:
    • I2C Kernelmodule laden (chose one of the following options):
      • I2C Kernelmodule laden:
        modules Datei öffnen
          sudo nano /etc/modules

        folgendes einfügen
          i2c-dev
          i2c-bcm2708
      • Seit Kernel 3.18.x auf dem Raspberry Pi und evtl. auch auf anderen Systemen ist der "Device tree support" implementiert und standardmäßig aktiviert. Um I2C Unterstützung zu aktivieren muß
          device_tree_param=i2c0=on,i2c1=on
        zur /boot/config.txt hinzu gefügt werden. Wenn nur einer der Busse genutzt wird, kann der andere einfach aus der Zeile entfernt werden.
      • Bei Raspbian Images seit 2015 kann der I2C Bus einfach über sudo raspi-config aktiviert werden. Die Parameter werden automatisch in die /boot/config.txt eingetragen.
      • Neustart

    • Eine der folgenden drei Möglichkeiten wählen um dem FHEM User Zugriff auf /dev/i2c-* zu geben:
      • sudo apt-get install i2c-tools
        sudo adduser fhem i2c


      • Folgende Zeilen entweder in die Datei /etc/init.d/fhem vor perl fhem.pl in start, oder in die Datei /etc/rc.local eingefügen:
        sudo chown fhem /dev/i2c-*
        sudo chgrp dialout /dev/i2c-*
        sudo chmod +t /dev/i2c-*
        sudo chmod 660 /dev/i2c-*

      • Für das Raspberry Pi kann alternativ das gpio Utility der WiringPi Bibliothek benutzt werden um FHEM Schreibrechte auf die I2C Schnittstelle zu bekommen.
        WiringPi Installation ist hier beschrieben: RPI_GPIO
        Das gpio Utility wird, wenn vorhanden, automatisch verwendet
        Wichtig: um den I2C-0 am P5 Stecker des Raspberry nutzen zu können muss das Attribut swap_i2c0 verwendet werden.

    • Optional: Hardwarezugriff via IOCTL wird standardmäßig genutzt (EMPFOHLEN), wenn Device::SMBus nicht installiert ist
      Soll der Hardwarezugriff über das Perl Modul Device::SMBus erfolgen sind diese Schritte notwendig:
        sudo apt-get install libmoose-perl
        sudo cpan Device::SMBus

    • Nur für Raspbian Nutzer
      Um I2C-0 am P5 Stecker auf Raspberry Pi modell B mit neueren Raspbian Versionen zu nutzen, welche auch das Raspberry Pi model B+ unterstützen, muss folgende Zeile in die /boot/cmdline.txt eingefügt werden:
        bcm2708.vc_i2c_override=1


    Define
      define <name> RPII2C <I2C Bus Number>
      Die <I2C Bus Number> ist die Nummer des I2C Bus an den die I2C IC's angeschlossen werden

    Set
    • Schreibe ein Byte (oder auch mehrere nacheinander) direkt auf ein I2C device (manche I2C Module sind so einfach, das es nicht einmal mehrere Register gibt):
      set <name> writeByte <I2C Address> <value>

    • Schreibe n-bytes auf einen Registerbereich (als Folge von Einzelbefehlen), beginnend mit dem angegebenen Register:
      set <name> writeByteReg <I2C Address> <Register Address> <value> [<value> [..]]

    • Schreibe n-bytes auf ein I2C device (als Blockoperation):
      set <name> writeBlock <I2C Address> <value> [<value> [..]]

    • Schreibe n-bytes auf einen Registerbereich (als Blockoperation), beginnend mit dem angegebenen Register:
      set <name> writeBlockReg <I2C Address> <Register Address> <value> [<value> [..]]


    • Beispiele:
        Schreibe 0xAA zu Modul mit I2C Addresse 0x60
        set test1 writeByte 60 AA
        Schreibe 0xAA zu Register 0x01 des Moduls mit der I2C Adresse 0x6E
        set test1 writeByteReg 6E 01 AA
        Schreibe 0xAA zu Register 0x01 des Moduls mit der I2C Adresse 0x6E, schreibe danach 0x55 in das Register 0x02 als einzelne Befehle
        set test1 writeByteReg 6E 01 AA 55
        Schreibe 0xA4 zu Register 0x03, 0x00 zu Register 0x04 und 0xDA zu Register 0x05 des Moduls mit der I2C Adresse 0x60 zusammen als ein Blockbefehl
        set test1 writeBlockReg 60 03 A4 00 DA

    Get
    • Auslesen der Registerinhalte des I2C Moduls:
      get <name> read <I2C Address> [<Register Address> [<number of registers>]]

    • Blockweises Auslesen des I2C Moduls (ohne separate Register):
      get <name> readblock <I2C Address> [<number of registers>]

    • Blockweises Auslesen der Registerinhalte des I2C Moduls:
      get <name> readblockreg <I2C Address> <Register Address> [<number of registers>]


    • Beispiele:
        Lese Byte vom Modul mit der I2C Adresse 0x60
        get test1 read 60
        Lese den Inhalt des Registers 0x01 vom Modul mit der I2C Adresse 0x6E.
        get test1 read 6E 01 AA 55
        Lese den Inhalt des Registerbereichs 0x03 bis 0x06 vom Modul mit der I2C Adresse 0x60.
        get test1 read 60 03 4


    Attribute
    • swap_i2c0
      Umschalten von I2C-0 des Raspberry Pi Rev. B von J5 auf P5
      Dieses Attribut ist nur für das Raspberry Pi vorgesehen und benötigt das gpio utility wie unter dem Punkt Vorbereitung beschrieben.
      Standard: keiner, gültige Werte: on, off

    • useHWLib
      Ändern der Methode des Hardwarezugriffs.
      Dieses Attribut existiert nur, wenn beide Zugriffsmethoden verfügbar sind
      Standard: IOCTL, gültige Werte: IOCTL, SMBus

    • ignore
    • do_not_notify
    • showtime

=end html_DE 1;