00_NetzerI2C.pm 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651
  1. ##############################################
  2. # $Id: 00_NetzerI2C.pm 15021 2017-09-06 19:48:55Z klausw $
  3. package main;
  4. use strict;
  5. use warnings;
  6. use Time::HiRes qw(gettimeofday);
  7. sub NetzerI2C_Attr(@);
  8. sub NetzerI2C_HandleQueue($);
  9. sub NetzerI2C_Read($);
  10. #sub NetzerI2C_Ready($);
  11. sub NetzerI2C_Write($$);
  12. #my $clientsI2C = ":I2C_PCF8574:I2C_PCA9532:I2C_BMP180:FHT.*:";
  13. #my %matchListI2C = (
  14. # "1:I2C_PCF8574"=> ".*",
  15. # "2:FHT" => "^81..(04|09|0d)..(0909a001|83098301|c409c401)..",
  16. #);
  17. my @clients = qw(
  18. I2C_LCD
  19. I2C_DS1307
  20. I2C_PC.*
  21. I2C_MCP.*
  22. I2C_BME280
  23. I2C_BMP180
  24. I2C_SHT21
  25. I2C_TSL2561
  26. I2C_LM.*
  27. );
  28. sub NetzerI2C_Initialize($) {
  29. my ($hash) = @_;
  30. require "$attr{global}{modpath}/FHEM/DevIo.pm";
  31. # Provider
  32. $hash->{Clients} = join (':',@clients);
  33. $hash->{ReadFn} = "NetzerI2C_Read"; #wird von der globalen loop aufgerufen (ueber $hash->{FD} gefunden), wenn Daten verfuegbar sind
  34. $hash->{WriteFn} = "NetzerI2C_Write"; #wird vom client per IOWrite($@) aufgerufen
  35. $hash->{ReadyFn} = "NetzerI2C_Ready";
  36. $hash->{I2CWrtFn} = "NetzerI2C_Write"; #zum testen als alternative fuer IOWrite
  37. # Normal devices
  38. $hash->{DefFn} = "NetzerI2C_Define";
  39. $hash->{UndefFn} = "NetzerI2C_Undef";
  40. $hash->{GetFn} = "NetzerI2C_Get";
  41. $hash->{SetFn} = "NetzerI2C_Set";
  42. $hash->{NotifyFn}= "NetzerI2C_Notify";
  43. $hash->{AttrFn} = "NetzerI2C_Attr";
  44. $hash->{AttrList}= "do_not_notify:1,0 dummy:1,0 " .
  45. "timeout socat:1,0";
  46. }
  47. #####################################
  48. sub NetzerI2C_Define($$) { #
  49. my ($hash, $def) = @_;
  50. my @a = split("[ \t][ \t]*", $def);
  51. unless(@a == 3) {
  52. my $msg = "wrong syntax: define <name> NetzerI2C {none | hostname:port}";
  53. Log3 undef, 2, $msg;
  54. return $msg;
  55. }
  56. DevIo_CloseDev($hash);
  57. my $name = $a[0];
  58. my $dev = $a[2];
  59. #$hash->{Clients} = $clientsI2C;
  60. #$hash->{MatchList} = \%matchListI2C;
  61. if($dev eq "none") {
  62. Log3 $name, 1, "$name device is none, commands will be echoed only";
  63. $attr{$name}{dummy} = 1;
  64. return undef;
  65. }
  66. $hash->{DeviceName} = $dev;
  67. #my $ret = DevIo_OpenDev($hash, 0, "CUL_DoInit");
  68. my $ret = DevIo_OpenDev($hash, 0, "");
  69. return $ret;
  70. }
  71. #####################################
  72. sub NetzerI2C_Notify { #
  73. my ($hash,$dev) = @_;
  74. my $name = $hash->{NAME};
  75. my $type = $hash->{TYPE};
  76. if( grep(m/^(INITIALIZED|REREADCFG)$/, @{$dev->{CHANGED}}) ) {
  77. NetzerI2C_forall_clients($hash,\&NetzerI2C_Init_Client,undef);;
  78. } elsif( grep(m/^SAVE$/, @{$dev->{CHANGED}}) ) {
  79. }
  80. }
  81. #####################################
  82. sub NetzerI2C_forall_clients($$$) { #
  83. my ($hash,$fn,$args) = @_;
  84. foreach my $d ( sort keys %main::defs ) {
  85. if ( defined( $main::defs{$d} )
  86. && defined( $main::defs{$d}{IODev} )
  87. && $main::defs{$d}{IODev} == $hash ) {
  88. &$fn($main::defs{$d},$args);
  89. }
  90. }
  91. return undef;
  92. }
  93. #####################################
  94. sub NetzerI2C_Init_Client($@) { #
  95. my ($hash,$args) = @_;
  96. if (!defined $args and defined $hash->{DEF}) {
  97. my @a = split("[ \t][ \t]*", $hash->{DEF});
  98. $args = \@a;
  99. }
  100. my $name = $hash->{NAME};
  101. Log3 $name,1,"im init client fuer $name ";
  102. my $ret = CallFn($name,"InitFn",$hash,$args);
  103. if ($ret) {
  104. Log3 $name,2,"error initializing '".$hash->{NAME}."': ".$ret;
  105. }
  106. }
  107. #####################################
  108. sub NetzerI2C_Undef($$) { #
  109. my ($hash, $arg) = @_;
  110. my $name = $hash->{NAME};
  111. foreach my $d (sort keys %defs) {
  112. if(defined($defs{$d}) &&
  113. defined($defs{$d}{IODev}) &&
  114. $defs{$d}{IODev} == $hash)
  115. {
  116. Log3 $name, 3, "deleting port for $d";
  117. delete $defs{$d}{IODev};
  118. }
  119. }
  120. DevIo_CloseDev($hash);
  121. return undef;
  122. }
  123. #####################################
  124. sub NetzerI2C_Set($@) { #
  125. my ($hash, @a) = @_;
  126. my $name = shift @a;
  127. my $type = shift @a;
  128. my $arg = join(" ", @a);
  129. my @sets = ('writeByte', 'writeByteReg', 'writeBlock');
  130. if($type eq "writeByte") {
  131. return "Usage: set $name i2csend <i2caddress> [<register address>] <data> [...<data>]"
  132. if(!$arg || $arg !~ /^[0-7][0-9A-F](\W[0-9A-F][0-9A-F]){0,64}$/xi);
  133. foreach (@a) {
  134. $_ = hex;
  135. }
  136. my $i2caddr = shift @a;
  137. my %sendpackage = ( i2caddress => $i2caddr, direction => "i2cwrite", data => join(" ", @a), direct=>1 );
  138. Log3 $hash, 1, "$sendpackage{data}";
  139. NetzerI2C_Write($hash, \%sendpackage);
  140. } elsif($type eq "writeByteReg") {
  141. return "Usage: set $name writeByteReg <i2caddress> <register address> <data> [...<data>]"
  142. if(!$arg || $arg !~ /^[0-7][0-9A-F](\W[0-9A-F][0-9A-F]){0,64}$/xi);
  143. foreach (@a) {
  144. $_ = hex;
  145. }
  146. my $i2caddr = shift @a;
  147. my $reg = shift @a;
  148. my %sendpackage = ( i2caddress => $i2caddr, direction => "i2cwrite", reg => $reg, data => join(" ", @a), direct=>1 );
  149. NetzerI2C_Write($hash, \%sendpackage);
  150. } elsif($type eq "writeBlock") {
  151. return "Usage: set $name writeBlock <i2caddress> <register address> <data> [...<data>]"
  152. if(!$arg || $arg !~ /^[0-7][0-9A-F](\W[0-9A-F][0-9A-F]){0,64}$/xi);
  153. foreach (@a) {
  154. $_ = hex;
  155. }
  156. my $i2caddr = shift @a;
  157. my $reg = shift @a;
  158. my %sendpackage = ( i2caddress => $i2caddr, direction => "i2cblockwrite", reg => $reg, data => join(" ", @a), direct=>1 );
  159. NetzerI2C_Write($hash, \%sendpackage);
  160. } else {
  161. return "Unknown argument $type, choose one of " . join(" ", @sets);
  162. }
  163. return undef;
  164. }
  165. #####################################
  166. sub NetzerI2C_Get($@) { #
  167. my ($hash, @a) = @_;
  168. my $nargs = int(@a);
  169. my $name = $hash->{NAME};
  170. my @gets = ('read');
  171. unless ( exists($a[1]) && $a[1] ne "?" && grep {/^$a[1]$/} @gets ) {
  172. return "Unknown argument $a[1], choose one of " . join(" ", @gets);
  173. }
  174. my ($msg, $err);
  175. return "No $a[1] for dummies" if(IsDummy($name));
  176. if ($a[1] eq "read") {
  177. return "use: \"get $name $a[1] <i2cAddress> [<RegisterAddress> [<Number od bytes to get>]]\"" if(@a < 3);
  178. return "$name I2C address must be 2-digit hexvalues" unless ($a[2] =~ /^(0x|)(|[0-7])[0-9A-F]$/xi); # && hex($a[2]) % 2 == 0);
  179. return "$name register address must be a hexvalues" if (defined($a[3]) && $a[3] !~ /^(0x|)[0-9A-F]{1,2}$/xi);
  180. return "$name number of bytes must be decimal value" if (defined($a[4]) && $a[4] !~ /^[0-9]{1,2}$/ && $a[4] < 65);
  181. my $hmsg = chr( (hex( $a[2] ) << 1) + 1 ); #I2C Adresse (read) in Zeichen wandeln
  182. if ( $a[3] ) { #Registeradresse in Hexwerte wandeln
  183. $hmsg .= chr( hex("5C") ) if ( (hex($a[3])) == "00"); #wenn 0x00 gesendet mit 0x5C escapen
  184. $hmsg .= chr( hex($a[3]) );
  185. }
  186. if ( $a[4] ) {
  187. for(my $n=1; $n<$a[4]; $n++) { #Fuer jedes zu lesende Byte ein Byte rausschicken
  188. $hmsg .= chr( hex("01") );
  189. }
  190. }
  191. $hmsg .= chr( hex("00") ); #Endezeichen anhaengen
  192. #nur zum testen mit socat#######################
  193. $hmsg =~ s/(.|\n)/sprintf("%.2X ",ord($1))/eg if ( AttrVal($hash->{NAME}, 'socat', 0) == 1 );
  194. ################################################
  195. DevIo_SimpleWrite($hash, $hmsg, undef);
  196. my $buf = undef;
  197. my $timeout = 10;
  198. return $hash->{NAME} . " disconnected" unless $hash->{FD};
  199. for(;;) { #Werte direkt lesen (mit Timeout)
  200. my $rin = "";
  201. vec($rin, $hash->{FD}, 1) = 1;
  202. my $nfound = select($rin, undef, undef, $timeout);
  203. last if($nfound <= 0);
  204. my $r = DevIo_DoSimpleRead($hash);
  205. if(!defined($r) || $r ne "") {
  206. $buf = $r;
  207. last;
  208. }
  209. }
  210. if ($buf) {
  211. if ( AttrVal($hash->{NAME}, 'socat', 0) == 0 ) {
  212. $buf =~ s/(.|\n)/sprintf("%.2X ",ord($1))/eg; #empfangene Zeichen in Hexwerte wandeln (fuer Socat auskommentieren)
  213. } else {
  214. chomp($buf); #weg nach testen mit Socat
  215. $buf = uc($buf); #weg nach testen mit Socat
  216. }
  217. my @abuf = split (/ /,$buf);
  218. for (my $i = 1; $i < (defined($a[3])? 3 : 2 ) ; $i++) { #pruefen, ob jedes gesendete Byte ein positives Ack bekommen hat
  219. return "error, no Ack received for $a[$1]; received: $buf" if $abuf[0] ne "FF";
  220. shift(@abuf);
  221. }
  222. my $rmsg = undef;
  223. my $nrec = int(@abuf);
  224. for (my $j = 0; $j < $nrec ; $j++) { #escape Zeichen fuer 0x00 entfernen
  225. $rmsg .= " " if (defined($rmsg));
  226. $rmsg .= $abuf[$j] unless( $abuf[$j] eq "5C" && defined($abuf[$j + 1]) && $abuf[$j + 1] eq "00" );
  227. }
  228. $buf = $rmsg;
  229. } else {
  230. $buf = "no Message received";
  231. }
  232. return $buf;
  233. }
  234. #$hash->{READINGS}{$a[1]}{VAL} = $msg;
  235. #$hash->{READINGS}{$a[1]}{TIME} = TimeNow();
  236. #return "$a[0] $a[1] => $msg";
  237. return undef;
  238. }
  239. #####################################
  240. sub NetzerI2C_DoInit($) { #ausfuehren beim start von devio evtl. loeschen oder reinit von clienten reinbauen
  241. my $hash = shift;
  242. my $name = $hash->{NAME};
  243. # Reset the counter
  244. delete($hash->{XMIT_TIME});
  245. delete($hash->{NR_CMD_LAST_H});
  246. return undef;
  247. }
  248. #####################################
  249. sub NetzerI2C_Write($$) { #wird vom Client aufgerufen
  250. my ($hash, $clientmsg) = @_;
  251. foreach my $av (keys %{$clientmsg}) { Log3 $hash, 5, "$hash->{NAME} vom Clienten: $av= " . $clientmsg->{$av}; }
  252. if ($clientmsg->{direction} && $clientmsg->{i2caddress}) {
  253. if(!$hash->{QQUEUE} || 0 == scalar(@{$hash->{QQUEUE}})) {
  254. $hash->{QQUEUE} = [ $clientmsg ];
  255. NetzerI2C_SendFromQueue($hash, $clientmsg);
  256. } else {
  257. push(@{$hash->{QQUEUE}}, $clientmsg);
  258. }
  259. }
  260. return undef;
  261. }
  262. #####################################
  263. sub NetzerI2C_SendFromQueue($$) { #
  264. my ($hash, $clientmsg) = @_;
  265. my $name = $hash->{NAME};
  266. my (@msg,@adata) = ();
  267. @adata = split(/ /,$clientmsg->{data}) if defined($clientmsg->{data});
  268. if (defined($clientmsg->{reg}) && ($clientmsg->{direction} eq "i2cwrite" && int(@adata) > 1)
  269. || ($clientmsg->{nbyte} && $clientmsg->{nbyte} > 1)) { #klaeren, ob Register sequentiell geschrieben werden
  270. $clientmsg->{smsg} = ( $clientmsg->{direction} eq "i2cwrite" ? int(@adata) : $clientmsg->{nbyte} ) if !$clientmsg->{smsg};
  271. $clientmsg->{smsgcnt}++;
  272. push(@msg, $clientmsg->{reg} + $clientmsg->{smsgcnt} - 1 ) if ($clientmsg->{reg}); #Registeradresse hochzaehlen wenn vorhanden
  273. push(@msg, $adata[$clientmsg->{smsgcnt} - 1]) if ($clientmsg->{direction} eq "i2cwrite");
  274. Log3 $hash, 5, $clientmsg->{direction} . " Nachricht zerteilen: ". ( defined($clientmsg->{data}) ? $clientmsg->{data} : "leer" ) ." Teil Nr: " .$clientmsg->{smsgcnt} ." = ". $clientmsg->{smsg};
  275. } else { #oder alle auf einmal
  276. Log3 $hash, 5, $clientmsg->{direction} . " Nachricht nicht zerteilen: ". ( defined($clientmsg->{data}) ? $clientmsg->{data} : "leer" ) ." Nbytes: " . int(@adata);
  277. push(@msg, $clientmsg->{reg} ) if defined($clientmsg->{reg});
  278. push(@msg, @adata);
  279. }
  280. my $hmsg = chr( ( $clientmsg->{i2caddress} << 1 ) + (($clientmsg->{direction} eq "i2cread")? 1 : 0) );
  281. if ( int(@msg) > 0 ) {
  282. foreach (@msg) { #Daten in Zeichen wandeln
  283. $hmsg .= chr( hex("5C") ) if ( $_ == hex("00") ); #wenn 0x00 gesendet mit 0x5C escapen
  284. $hmsg .= chr( $_ );
  285. }
  286. }
  287. $hmsg .= chr( hex("00") ); #Endezeichen anhaengen
  288. #nur zum Testen########
  289. $clientmsg->{bytecount} = int(@msg) + 1; #Anzahl Nutzdaten + Adressbyte
  290. (my $smsg = $hmsg) =~ s/(.|\n)/sprintf("%.2X ",ord($1))/eg;
  291. Log3 $hash, 5, "$name SendFromQueue: $clientmsg->{direction}, String: $smsg, Hex: $hmsg, NBytes: $clientmsg->{bytecount}";
  292. #######################
  293. #DevIo_SimpleWrite($hash, $hmsg, undef);
  294. DevIo_SimpleWrite($hash, AttrVal($hash->{NAME}, 'socat', 0) == 1 ? $smsg : $hmsg, undef); #fuer Socat zum testen
  295. NetzerI2C_InternalTimer("RecvTimeout", gettimeofday() + AttrVal($hash->{NAME}, 'timeout', 10), "NetzerI2C_TransceiveTimeout", $hash, 0);
  296. }
  297. #####################################
  298. sub NetzerI2C_HandleQueue($) { #
  299. my $hash = shift;
  300. my $arr = $hash->{QQUEUE};
  301. if(defined($arr) && @{$arr} > 0) {
  302. shift(@{$arr}) unless $arr->[0]->{smsg} && $arr->[0]->{smsg} > $arr->[0]->{smsgcnt}; #nur auf naechste Botschaft wechseln wenn alle Byte gesendet wurden
  303. if(@{$arr} == 0) {
  304. delete($hash->{QQUEUE});
  305. return;
  306. }
  307. my $clientmsg = $arr->[0];
  308. if(defined($clientmsg) && $clientmsg eq "") {
  309. NetzerI2C_HandleQueue($hash) if defined($hash);
  310. } else {
  311. NetzerI2C_SendFromQueue($hash, $clientmsg);
  312. }
  313. }
  314. }
  315. #####################################
  316. sub NetzerI2C_TransceiveTimeout($) {#
  317. #my $hash = shift;
  318. #Hash finden wenn myinternaltimer genutzt wird#
  319. my ($myHash) = @_; #
  320. my $hash = $myHash->{HASH}; #
  321. ###############################################
  322. my $name = $hash->{NAME};
  323. Log3 $hash, 1, "$name: Timeout I2C response";
  324. my $arr = $hash->{QQUEUE};
  325. delete $arr->[0]->{smsg} if $arr->[0]->{smsg};
  326. NetzerI2C_HandleQueue($hash);
  327. }
  328. #####################################
  329. sub NetzerI2C_Read($) { # called from the global loop, when the select for hash->{FD} reports data
  330. my ($hash) = @_;
  331. my $buf = DevIo_SimpleRead($hash);
  332. return undef if(!defined($buf)); #Aendern????
  333. #Log3 $hash, 1, "$hash->{NAME} vom I2C empfangen 1: $buf";
  334. #hier noch abfangen, wenn $buf leer ist
  335. if ( AttrVal($hash->{NAME}, 'socat', 0) == 1 ) { #weg nach testen mit Socat
  336. chomp($buf);
  337. #$buf = hex($buf);
  338. } else {
  339. $buf =~ s/(.|\n)/sprintf("%.2X ",ord($1))/eg #empfangene Zeichen in Hexwerte wandeln -> in wandlung nach Zahl aendern
  340. }
  341. Log3 $hash, 5, "$hash->{NAME} vom I2C empfangen: $buf";
  342. my @abuf = split (/ /,$buf);
  343. foreach (@abuf) { #weg wenn Zeichen direkt gewandelt werden
  344. $_ = hex;
  345. #Log3 $hash, 1, "$hash->{NAME} vom I2C: $_";
  346. }
  347. my $name = $hash->{NAME};
  348. #Log3 $hash, 1, "$hash->{NAME} vom I2C empfangen: $buf";
  349. my $arr = $hash->{QQUEUE};
  350. if(defined($arr) && @{$arr} > 0) {
  351. my $clientmsg = $arr->[0];
  352. NetzerI2C_RemoveInternalTimer("RecvTimeout", $hash);
  353. my $status = "Ok";
  354. for (my $i = 0; $i < $clientmsg->{bytecount} ; $i++) { #pruefen, ob jedes gesendete Byte ein positives Ack (FF) bekommen hat
  355. $status = "error" . ($arr->[0]->{smsg} ? "@ reg: ". sprintf("%.2X ",($clientmsg->{reg} + $clientmsg->{smsgcnt} - 1)) :"") if !defined($abuf[0]) || $abuf[0] != 255;
  356. shift(@abuf);
  357. }
  358. my $rmsg = undef;
  359. my $nrec = int(@abuf);
  360. for (my $i = 0; $i < $nrec ; $i++) { #escape Zeichen (0x5C) fuer 0x00 entfernen
  361. $rmsg .= " " if (defined($rmsg));
  362. #$rmsg .= $abuf[$i] unless( $abuf[$i] eq "5C" && defined($abuf[$i + 1]) && $abuf[$i + 1] eq "00" );
  363. $rmsg .= $abuf[$i] unless( $abuf[$i] == 92 && defined($abuf[$i + 1]) && $abuf[$i + 1] == 0 );
  364. }
  365. if ( $arr->[0]->{smsg} && defined($rmsg) ) { #wenn Nachricht Teil einer Nachrichtenfolge, dann Daten anhaengen
  366. $clientmsg->{received} .= ( defined($arr->[0]->{smsg}) && $arr->[0]->{smsg} == 1 ? "" : " ") . $rmsg;
  367. } else {
  368. $clientmsg->{received} = $rmsg;
  369. }
  370. unless ( $arr->[0]->{smsg} && $arr->[0]->{smsg} > $arr->[0]->{smsgcnt} && $status eq "Ok" ) { #erst senden, wenn Transfer abgeschlossen oder bei Fehler
  371. delete $arr->[0]->{smsg} if $arr->[0]->{smsg} && $status ne "Ok"; #aktuellen Einzeltransfer durch loeschen der Botschaftszahl abbrechen
  372. #$clientmsg->{received} = $rmsg if defined($rmsg);
  373. $clientmsg->{$name . "_" . "RAWMSG"} = $buf;
  374. $clientmsg->{$name . "_" . "SENDSTAT"} = $status;
  375. if ($clientmsg->{direct}) { #Vorgang wurde von diesem Modul ausgeloest
  376. $hash->{direct_send} = $clientmsg->{data};
  377. $hash->{direct_answer} = $clientmsg->{$name . "_" . "RAWMSG"};
  378. $hash->{direct_I2Caddr} = $clientmsg->{i2caddress};
  379. $hash->{direct_SENDSTAT} = $status;
  380. }
  381. ########################################### neue Variante zum senden an client
  382. foreach my $d ( sort keys %main::defs ) { #zur Botschaft passenden Clienten ermitteln geht auf Client: I2CRecFn
  383. #Log3 $hash, 1, "Clients suchen 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}" : "");
  384. if ( defined( $main::defs{$d} )
  385. && defined( $main::defs{$d}{IODev} ) && $main::defs{$d}{IODev} == $hash
  386. && defined( $main::defs{$d}{I2C_Address} ) && defined( $clientmsg->{i2caddress} )
  387. && $main::defs{$d}{I2C_Address} eq $clientmsg->{i2caddress} ) {
  388. my $chash = $main::defs{$d};
  389. Log3 $hash, 5, "Client gefunden 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}" : "");
  390. CallFn($d, "I2CRecFn", $chash, $clientmsg);
  391. }
  392. }
  393. ######################################## alte Variante ueber Dispatch ######################
  394. # my $dir = $clientmsg->{direction}; #
  395. # my $sid = $clientmsg->{id}; #
  396. # if($dir eq "i2cread" || $dir eq "i2cwrite") { #
  397. # my $dev = $clientmsg->{i2caddress}; #
  398. # my %addvals = (RAWMSG => $buf, SENDSTAT => $status); #
  399. # $rmsg = ( defined($rmsg) ? ($sid . " " . $dev . " " . $rmsg) : ($sid . " " . $dev) ); #
  400. # Log 1, "wird an Client geschickt: $rmsg"; #
  401. # Dispatch($hash, $rmsg, \%addvals); #
  402. # } #
  403. ###########################################################################################
  404. undef $clientmsg; #Hash loeschen nachdem Daten verteilt wurden
  405. }
  406. NetzerI2C_HandleQueue($hash);
  407. } else {
  408. Log3 $hash, 1, "$name: unknown data received: $buf";
  409. }
  410. }
  411. #####################################
  412. sub NetzerI2C_Ready($) {############# kann geloescht werden?
  413. my ($hash) = @_;
  414. return DevIo_OpenDev($hash, 1, "")
  415. if($hash->{STATE} eq "disconnected");
  416. # This is relevant for windows/USB only
  417. my $po = $hash->{USBDev};
  418. my ($BlockingFlags, $InBytes, $OutBytes, $ErrorFlags);
  419. if($po) {
  420. ($BlockingFlags, $InBytes, $OutBytes, $ErrorFlags) = $po->status;
  421. }
  422. return ($InBytes && $InBytes>0);
  423. }
  424. #####################################
  425. sub NetzerI2C_Attr(@) { #
  426. my ($cmd,$name,$aName,$aVal) = @_;
  427. my $msg = undef;
  428. if($aName eq "timeout") {
  429. if ( defined($aVal) ) {
  430. unless ( looks_like_number($aVal) && $aVal >= 0.1 && $aVal <= 20 ) {
  431. $msg = "$name: Wrong $aName defined. Value must be a number between 0.1 and 20";
  432. }
  433. }
  434. }
  435. return $msg;
  436. }
  437. #####################################
  438. sub NetzerI2C_InternalTimer($$$$$) {#(von Dietmar63)
  439. my ($modifier, $tim, $callback, $hash, $waitIfInitNotDone) = @_;
  440. my $mHash;
  441. if ($modifier eq "") {
  442. $mHash = $hash;
  443. } else {
  444. my $timerName = "$hash->{NAME}_$modifier";
  445. if (exists ($hash->{TIMER}{$timerName})) {
  446. $mHash = $hash->{TIMER}{$timerName};
  447. } else {
  448. $mHash = { HASH=>$hash, NAME=>"$hash->{NAME}_$modifier", MODIFIER=>$modifier};
  449. $hash->{TIMER}{$timerName} = $mHash;
  450. }
  451. }
  452. InternalTimer($tim, $callback, $mHash, $waitIfInitNotDone);
  453. }
  454. #####################################
  455. sub NetzerI2C_RemoveInternalTimer($$) {
  456. my ($modifier, $hash) = @_;
  457. my $timerName = "$hash->{NAME}_$modifier";
  458. if ($modifier eq "") {
  459. RemoveInternalTimer($hash);
  460. } else {
  461. my $myHash = $hash->{TIMER}{$timerName};
  462. if (defined($myHash)) {
  463. delete $hash->{TIMER}{$timerName};
  464. RemoveInternalTimer($myHash);
  465. }
  466. }
  467. }
  468. 1;
  469. =pod
  470. =item device
  471. =item summary accesses I2C interface on an Netzer
  472. =item summary_DE Zugriff auf das I2C-Interface einer Netzer
  473. =begin html
  474. <a name="NetzerI2C"></a>
  475. <h3>NetzerI2C</h3>
  476. <ul>
  477. <a name="NetzerI2C"></a>
  478. Provides access to <a href="http://www.mobacon.de/wiki/doku.php/en/netzer/index">Netzer's</a> I2C interfaces for some logical modules and also directly.<br><br>
  479. <b>preliminary:</b><br>
  480. Serial Server of Netzer must be <a href="http://www.mobacon.de/wiki/doku.php/en/netzer/serialserveraktiviert"> activated and configured for I2C </a>.<br>
  481. <a name="NetzerI2CDefine"></a><br>
  482. <b>Define</b>
  483. <ul>
  484. <code>define &lt;name&gt; NetzerI2C &lt;Device-Address:Port&gt;</code><br>
  485. where <code>&lt;Device-Address:Port&gt;</code> Device Address/ IP-Address and Serial Server TCP Port of the Netzer<br><br>
  486. </ul>
  487. <a name="NetzerI2CSet"></a>
  488. <b>Set</b>
  489. <ul>
  490. <li>
  491. Write one byte (or more bytes sequentially) directly to an I2C device (for devices that have only one register to write):<br>
  492. <code>set &lt;name&gt; writeByte &lt;I2C Address&gt; &lt;value&gt;</code><br><br>
  493. </li>
  494. <li>
  495. Write one byte (or more bytes sequentially) to the specified register of an I2C device:<br>
  496. <code>set &lt;name&gt; writeByteReg &lt;I2C Address&gt; &lt;Register Address&gt; &lt;value&gt;</code><br><br>
  497. </li>
  498. <li>
  499. Write n-bytes to an register range, beginning at the specified register:<br>
  500. <code>set &lt;name&gt; writeBlock &lt;I2C Address&gt; &lt;Register Address&gt; &lt;value&gt;</code><br><br>
  501. </li>
  502. Examples:
  503. <ul>
  504. Write 0xAA to device with I2C address 0x60<br>
  505. <code>set test1 writeByte 60 AA</code><br>
  506. Write 0xAA to register 0x01 of device with I2C address 0x6E<br>
  507. <code>set test1 writeByteReg 6E 01 AA</code><br>
  508. Write 0xAA to register 0x01 of device with I2C address 0x6E, after it write 0x55 to register 0x02<br>
  509. <code>set test1 writeByteReg 6E 01 AA 55</code><br>
  510. Write 0xA4 to register 0x03, 0x00 to register 0x04 and 0xDA to register 0x05 of device with I2C address 0x60 as block operation<br>
  511. <code>set test1 writeBlock 60 03 A4 00 DA</code><br>
  512. </ul><br>
  513. </ul>
  514. <a name="NetzerI2CGet"></a>
  515. <b>Get</b>
  516. <ul>
  517. <code>get &lt;name&gt; read &lt;I2C Address&gt; [&lt;Register Address&gt; [&lt;number of registers&gt;]] </code>
  518. <br>
  519. gets value of I2C device's registers<br><br>
  520. Examples:
  521. <ul>
  522. Reads byte from device with I2C address 0x60<br>
  523. <code>get test1 writeByte 60</code><br>
  524. Reads register 0x01 of device with I2C address 0x6E.<br>
  525. <code>get test1 read 6E 01 AA 55</code><br>
  526. Reads register 0x03 to 0x06 of device with I2C address 0x60.<br>
  527. <code>get test1 read 60 03 4</code><br>
  528. </ul><br>
  529. </ul><br>
  530. <a name="NetzerI2CAttr"></a>
  531. <b>Attributes</b>
  532. <ul>
  533. <li><a href="#ignore">ignore</a></li>
  534. <li><a href="#do_not_notify">do_not_notify</a></li>
  535. <li><a href="#showtime">showtime</a></li>
  536. </ul>
  537. <br>
  538. </ul>
  539. =end html
  540. =begin html_DE
  541. <a name="NetzerI2C"></a>
  542. <h3>NetzerI2C</h3>
  543. <ul>
  544. <a name="NetzerI2C"></a>
  545. Erm&ouml;glicht den Zugriff auf die I2C Schnittstelle des <a href="http://www.mobacon.de/wiki/doku.php/de/netzer/index">Netzer</a>.<br> &uuml;ber logische Module. Register von I2C IC's k&ouml;nnen auch direkt gelesen und geschrieben werden.<br><br>
  546. <b>Vorbereitung:</b><br>
  547. Bevor dieses Modul verwendet werden kann muss der Serielle Server des Netzers <a href="http://www.mobacon.de/wiki/doku.php/de/netzer/serialserveraktiviert"> und auf I2C gestellt</a> werden.
  548. <a name="NetzerI2CDefine"></a><br><br>
  549. <b>Define</b>
  550. <ul>
  551. <code>define &lt;name&gt; NetzerI2C &lt;Device-Address:Port&gt;</code><br>
  552. <code>&lt;Device-Address:Port&gt;</code> ist die Adresse/IP-Adresse und Serial Server TCP-Port des Netzer<br><br>
  553. </ul>
  554. <a name="NetzerI2CSet"></a>
  555. <b>Set</b>
  556. <ul>
  557. <li>
  558. 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):<br>
  559. <code>set &lt;name&gt; writeByte &lt;I2C Address&gt; &lt;value&gt;</code><br><br>
  560. </li>
  561. <li>
  562. Schreibe ein Byte (oder auch mehrere nacheinander) direkt auf ein Register des adressierten I2C device:<br>
  563. <code>set &lt;name&gt; writeByteReg &lt;I2C Address&gt; &lt;Register Address&gt; &lt;value&gt;</code><br><br>
  564. </li>
  565. <li>
  566. Schreibe n-bytes auf einen Registerbereich, beginnend mit dem angegebenen Register:<br>
  567. <code>set &lt;name&gt; writeBlock &lt;I2C Address&gt; &lt;Register Address&gt; &lt;value&gt;</code><br><br>
  568. </li>
  569. Beispiele:
  570. <ul>
  571. Schreibe 0xAA zu Modul mit I2C Addresse 0x60<br>
  572. <code>set test1 writeByte 60 AA</code><br>
  573. Schreibe 0xAA zu Register 0x01 des Moduls mit der I2C Adresse 0x6E<br>
  574. <code>set test1 writeByteReg 6E 01 AA</code><br>
  575. Schreibe 0xAA zu Register 0x01 des Moduls mit der I2C Adresse 0x6E, schreibe danach 0x55 zu Register 0x01<br>
  576. <code>set test1 writeByteReg 6E 01 AA 55</code><br>
  577. Schreibe 0xA4 zu Register 0x03, 0x00 zu Register 0x04 und 0xDA zu Register 0x05 des Moduls mit der I2C Adresse 0x60 als Block<br>
  578. <code>set test1 writeBlock 60 03 A4 00 DA</code><br>
  579. </ul><br>
  580. </ul>
  581. <a name="NetzerI2CGet"></a>
  582. <b>Get</b>
  583. <ul>
  584. <code>get &lt;name&gt; read &lt;I2C Address&gt; [&lt;Register Address&gt; [&lt;number of registers&gt;]] </code>
  585. <br>
  586. Auslesen der Registerinhalte des I2C Moduls<br><br>
  587. Examples:
  588. <ul>
  589. Lese Byte vom Modul mit der I2C Adresse 0x60<br>
  590. <code>get test1 writeByte 60</code><br>
  591. Lese den Inhalt des Registers 0x01 vom Modul mit der I2C Adresse 0x6E.<br>
  592. <code>get test1 read 6E 01 AA 55</code><br>
  593. Lese den Inhalt des Registerbereichs 0x03 bis 0x06 vom Modul mit der I2C Adresse 0x60.<br>
  594. <code>get test1 read 60 03 4</code><br>
  595. </ul><br>
  596. </ul><br>
  597. <a name="NetzerI2CAttr"></a>
  598. <b>Attribute</b>
  599. <ul>
  600. <li><a href="#ignore">ignore</a></li>
  601. <li><a href="#do_not_notify">do_not_notify</a></li>
  602. <li><a href="#showtime">showtime</a></li>
  603. </ul>
  604. <br>
  605. </ul>
  606. =end html_DE