44_S7_DRead.pm 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506
  1. # $Id: 44_S7_DRead.pm 12776 2016-12-14 18:09:08Z charlie71born $
  2. ##############################################
  3. package main;
  4. use strict;
  5. use warnings;
  6. #use Switch;
  7. #use 44_S7_Client;
  8. my %gets = (
  9. # "libnodaveversion" => ""
  10. );
  11. #####################################
  12. sub S7_DRead_Initialize($) {
  13. my $hash = shift @_;
  14. # Provider
  15. # Consumer
  16. $hash->{Match} = "^DR";
  17. $hash->{DefFn} = "S7_DRead_Define";
  18. $hash->{UndefFn} = "S7_DRead_Undef";
  19. $hash->{ParseFn} = "S7_DRead_Parse";
  20. $hash->{AttrFn} = "S7_DRead_Attr";
  21. $hash->{AttrList} = "IODev " . $readingFnAttributes;
  22. main::LoadModule("S7");
  23. }
  24. #####################################
  25. sub S7_DRead_Define($$) {
  26. my ( $hash, $def ) = @_;
  27. my @a = split( "[ \t][ \t]*", $def );
  28. my ( $name, $area, $DB, $start, $position );
  29. $name = $a[0];
  30. AssignIoPort($hash); # logisches modul an physikalisches binden !!!
  31. my $sname = $hash->{IODev}{NAME};
  32. my $byte;
  33. my $bit;
  34. if ( uc $a[2] =~ m/^[QIMN](\d*)/ ) {
  35. my $Offset;
  36. $area = "db";
  37. $DB = 0;
  38. my $startposition;
  39. if ( uc $a[2] =~ m/^Q(\d*)/ ) {
  40. $startposition = 1;
  41. if ( defined($hash->{IODev}{S7TYPE}) && $hash->{IODev}{S7TYPE} eq "LOGO7" ) {
  42. $Offset = 942;
  43. }
  44. elsif ( defined($hash->{IODev}{S7TYPE}) && $hash->{IODev}{S7TYPE} eq "LOGO8" ) {
  45. $Offset = 1064;
  46. }
  47. else {
  48. my $msg =
  49. "wrong syntax : define <name> S7_DRead {inputs|outputs|flags|db} <DB> <address> \n Only for Logo7 or Logo8:\n define <name> S7_DRead {I|Q|M|NI|NQ}1..24";
  50. Log3 undef, 2, $msg;
  51. return $msg;
  52. }
  53. }
  54. elsif ( uc $a[2] =~ m/^I(\d*)/ ) {
  55. $startposition = 1;
  56. if ( $hash->{IODev}{S7TYPE} eq "LOGO7" ) {
  57. $Offset = 923;
  58. }
  59. elsif ( $hash->{IODev}{S7TYPE} eq "LOGO8" ) {
  60. $Offset = 1024;
  61. }
  62. else {
  63. my $msg =
  64. "wrong syntax : define <name> S7_DRead {inputs|outputs|flags|db} <DB> <address> \n Only for Logo7 or Logo8:\n define <name> S7_DRead {I|Q|M|NI|NQ}1..24";
  65. Log3 undef, 2, $msg;
  66. return $msg;
  67. }
  68. }
  69. elsif ( uc $a[2] =~ m/^NI(\d*)/ ) {
  70. $startposition = 2;
  71. if ( $hash->{IODev}{S7TYPE} eq "LOGO8" ) {
  72. $Offset = 1246;
  73. }
  74. else {
  75. my $msg =
  76. "wrong syntax : define <name> S7_DRead {inputs|outputs|flags|db} <DB> <address> \n Only for Logo7 or Logo8:\n define <name> S7_DRead {I|Q|M|NI|NQ}1..24";
  77. Log3 undef, 2, $msg;
  78. return $msg;
  79. }
  80. }
  81. elsif ( uc $a[2] =~ m/^NQ(\d*)/ ) {
  82. $startposition = 2;
  83. if ( $hash->{IODev}{S7TYPE} eq "LOGO8" ) {
  84. $Offset = 1390;
  85. }
  86. else {
  87. my $msg =
  88. "wrong syntax : define <name> S7_DRead {inputs|outputs|flags|db} <DB> <address> \n Only for Logo7 or Logo8:\n define <name> S7_DRead {I|Q|M|NI|NQ}1..24";
  89. Log3 undef, 2, $msg;
  90. return $msg;
  91. }
  92. }
  93. elsif ( uc $a[2] =~ m/^M(\d*)/ ) {
  94. $startposition = 1;
  95. if ( $hash->{IODev}{S7TYPE} eq "LOGO7" ) {
  96. $Offset = 948;
  97. }
  98. elsif ( $hash->{IODev}{S7TYPE} eq "LOGO8" ) {
  99. $Offset = 1104;
  100. }
  101. else {
  102. my $msg =
  103. "wrong syntax : define <name> S7_DRead {inputs|outputs|flags|db} <DB> <address> \n Only for Logo7 or Logo8:\n define <name> S7_DRead {I|Q|M|NI|NQ}1..24";
  104. Log3 undef, 2, $msg;
  105. return $msg;
  106. }
  107. }
  108. else {
  109. my $msg =
  110. "wrong syntax : define <name> S7_DRead {inputs|outputs|flags|db} <DB> <address> \n Only for Logo7 or Logo8:\n define <name> S7_DRead {I|Q|M|NI|NQ}1..24";
  111. Log3 undef, 2, $msg;
  112. return $msg;
  113. }
  114. $position =
  115. ( $Offset * 8 ) + int( substr( $a[2], $startposition ) ) - 1;
  116. $byte = int( $position / 8 );
  117. $bit = ( $position % 8 );
  118. }
  119. else {
  120. $area = lc $a[2];
  121. $DB = $a[3];
  122. $position = $a[4];
  123. if ( $area ne "inputs"
  124. && $area ne "outputs"
  125. && $area ne "flags"
  126. && $area ne "db" )
  127. {
  128. my $msg =
  129. "wrong syntax : define <name> S7_DRead {inputs|outputs|flags|db} <DB> <address> \n Only for Logo7 or Logo8:\n define <name> S7_DRead {I|Q|M|NI|NQ}1..24";
  130. Log3 undef, 2, $msg;
  131. return $msg;
  132. }
  133. my @address = split( /\./, $position );
  134. if ( int(@address) == 2 ) {
  135. $byte = $address[0];
  136. $bit = $address[1];
  137. }
  138. else {
  139. $byte = int( $address[0] / 8 );
  140. $bit = ( $address[0] % 8 );
  141. }
  142. }
  143. $hash->{AREA} = $area;
  144. $hash->{DB} = $DB;
  145. $hash->{POSITION} = ( $byte * 8 ) + $bit;
  146. $hash->{ADDRESS} = "$byte.$bit";
  147. $hash->{LENGTH} = 1;
  148. my $ID = "$area $DB";
  149. if ( !defined( $modules{S7_DRead}{defptr}{$ID} ) ) {
  150. my @b = ();
  151. push( @b, $hash );
  152. $modules{S7_DRead}{defptr}{$ID} = \@b;
  153. }
  154. else {
  155. push( @{ $modules{S7_DRead}{defptr}{$ID} }, $hash );
  156. }
  157. $hash->{IODev}{dirty} = 1;
  158. Log3 $name, 4, "S7_DRead ($sname): define $name Adress:$byte.$bit";
  159. return undef;
  160. }
  161. #####################################
  162. sub S7_DRead_Undef($$) {
  163. my ( $hash, $name ) = @_;
  164. Log3 $name, 4,
  165. "S7_DRead ("
  166. . $hash->{IODev}{NAME}
  167. . "): undef "
  168. . $hash->{NAME}
  169. . " Adress:"
  170. . $hash->{ADDRESS};
  171. delete( $modules{S7_DRead}{defptr} );
  172. return undef;
  173. }
  174. #####################################
  175. sub S7_DRead_Parse_new($$) {
  176. my ( $hash, $rmsg ) = @_;
  177. my $name;
  178. if ( defined( $hash->{NAME} ) ) {
  179. $name = $hash->{NAME};
  180. }
  181. else {
  182. Log3 undef, 2, "S7_DRead: Error ...";
  183. return undef;
  184. }
  185. my @a = split( "[ \t][ \t]*", $rmsg );
  186. my @list;
  187. my ( $area, $DB, $start, $length, $datatype, $s7name, $hexbuffer );
  188. $area = lc $a[1];
  189. $DB = $a[2];
  190. $start = $a[3];
  191. $length = $a[4];
  192. $s7name = $a[5];
  193. $hexbuffer = $a[6];
  194. my $ID = "$area $DB";
  195. Log3 $name, 6, "$name S7_DRead_Parse $rmsg";
  196. my @Writebuffer =
  197. unpack( "C" x $length, pack( "H2" x $length, split( ",", $hexbuffer ) ) );
  198. # my $b = pack( "C" x $length, @Writebuffer );
  199. my $clientArray = $hash->{"Clients"};
  200. foreach my $h ( @{$clientArray} ) {
  201. if ( $start <= int( $h->{POSITION} / 8 )
  202. && $start + $length >= int( $h->{POSITION} / 8 ) )
  203. {
  204. #die Nachricht ist für den client
  205. my $n = $h->{NAME}; #damit die werte im client gesetzt werden!
  206. push( @list, $n );
  207. #aktualisierung des wertes
  208. my $s = int( $h->{POSITION} / 8 ) - $start;
  209. my $myI = $hash->{S7PLCClient}->ByteAt( \@Writebuffer, $s );
  210. Log3 $name, 6, "$name S7_DRead_Parse update $n ";
  211. if ( ( int($myI) & ( 1 << ( $h->{POSITION} % 8 ) ) ) > 0 ) {
  212. main::readingsSingleUpdate( $h, "state", "on", 1 );
  213. }
  214. else {
  215. main::readingsSingleUpdate( $h, "state", "off", 1 );
  216. }
  217. }
  218. }
  219. if ( int(@list) == 0 ) {
  220. Log3 $name, 6, "S7_DRead: Parse no client found ($name) ...";
  221. push( @list, "" );
  222. }
  223. return @list;
  224. }
  225. #####################################
  226. sub S7_DRead_Parse($$) {
  227. my ( $hash, $rmsg ) = @_;
  228. my $name;
  229. if ( defined( $hash->{NAME} ) ) {
  230. $name = $hash->{NAME};
  231. }
  232. else {
  233. Log3 undef, 2, "S7_DRead: Error ...";
  234. return undef;
  235. }
  236. my @a = split( "[ \t][ \t]*", $rmsg );
  237. my @list;
  238. my ( $area, $DB, $start, $length, $datatype, $s7name, $hexbuffer,
  239. $clientNames );
  240. $area = lc $a[1];
  241. $DB = $a[2];
  242. $start = $a[3];
  243. $length = $a[4];
  244. $s7name = $a[5];
  245. $hexbuffer = $a[6];
  246. $clientNames = $a[7];
  247. my $ID = "$area $DB";
  248. Log3 $name, 5, "$name S7_DRead_Parse $rmsg";
  249. # main::readingsBeginUpdate($h);
  250. # main::readingsBulkUpdate($h,"reading",$res,1);
  251. # main::readingsEndUpdate($h, 1);
  252. my @clientList = split( ",", $clientNames );
  253. if ( int(@clientList) > 0 ) {
  254. my @Writebuffer = unpack( "C" x $length,
  255. pack( "H2" x $length, split( ",", $hexbuffer ) ) );
  256. foreach my $clientName (@clientList) {
  257. my $h = $defs{$clientName};
  258. # if ( defined( $main::attr{ $h->{NAME} }{IODev} )
  259. # && $main::attr{ $h->{NAME} }{IODev} eq $name )
  260. # {
  261. if ( $h->{TYPE} eq "S7_DRead"
  262. && $start <= int( $h->{POSITION} / 8 )
  263. && $start + $length >= int( $h->{POSITION} / 8 ) )
  264. {
  265. push( @list, $clientName )
  266. ; #damit die werte im client gesetzt werden!
  267. #aktualisierung des wertes
  268. my $s = int( $h->{POSITION} / 8 ) - $start;
  269. my $myI = $hash->{S7PLCClient}->ByteAt( \@Writebuffer, $s );
  270. Log3 $name, 6, "$name S7_DRead_Parse update $clientName ";
  271. if ( ( int($myI) & ( 1 << ( $h->{POSITION} % 8 ) ) ) > 0 ) {
  272. main::readingsSingleUpdate( $h, "state", "on", 1 );
  273. }
  274. else {
  275. main::readingsSingleUpdate( $h, "state", "off", 1 );
  276. }
  277. }
  278. # }
  279. }
  280. }
  281. else {
  282. Log3 $name, 3, "$name S7_DRead_Parse going the save way ";
  283. if ( defined( $modules{S7_DRead}{defptr}{$ID} ) ) {
  284. foreach my $h ( @{ $modules{S7_DRead}{defptr}{$ID} } ) {
  285. if ( defined( $main::attr{ $h->{NAME} }{IODev} )
  286. && $main::attr{ $h->{NAME} }{IODev} eq $name )
  287. {
  288. if ( $start <= int( $h->{POSITION} / 8 )
  289. && $start + $length >= int( $h->{POSITION} / 8 ) )
  290. {
  291. my $n =
  292. $h->{NAME}; #damit die werte im client gesetzt werden!
  293. push( @list, $n );
  294. #aktualisierung des wertes
  295. my @Writebuffer = unpack( "C" x $length,
  296. pack( "H2" x $length, split( ",", $hexbuffer ) ) );
  297. my $s = int( $h->{POSITION} / 8 ) - $start;
  298. #my $b = pack( "C" x $length, @Writebuffer );
  299. my $myI =
  300. $hash->{S7PLCClient}->ByteAt( \@Writebuffer, $s );
  301. Log3 $name, 6, "$name S7_DRead_Parse update $n ";
  302. if ( ( int($myI) & ( 1 << ( $h->{POSITION} % 8 ) ) ) >
  303. 0 )
  304. {
  305. main::readingsSingleUpdate( $h, "state", "on", 1 );
  306. }
  307. else {
  308. main::readingsSingleUpdate( $h, "state", "off", 1 );
  309. }
  310. }
  311. }
  312. }
  313. }
  314. }
  315. if ( int(@list) == 0 ) {
  316. Log3 $name, 6, "S7_DRead: Parse no client found ($name) ...";
  317. push( @list, "" );
  318. }
  319. return @list;
  320. }
  321. #####################################
  322. sub S7_DRead_Attr(@) {
  323. my ( $cmd, $name, $aName, $aVal ) = @_;
  324. # $cmd can be "del" or "set"
  325. # $name is device name
  326. # aName and aVal are Attribute name and value
  327. my $hash = $defs{$name};
  328. if ( $cmd eq "set" ) {
  329. if ( $aName eq "IODev" ) {
  330. if ( defined( $hash->{IODev} ) ) { #set old master device dirty
  331. $hash->{IODev}{dirty} = 1;
  332. }
  333. if ( defined( $defs{$aVal} ) ) { #set new master device dirty
  334. $defs{$aVal}{dirty} = 1;
  335. }
  336. Log3 $name, 4, "S7_DRead: IODev for $name is $aVal";
  337. }
  338. }
  339. return undef;
  340. }
  341. #####################################
  342. 1;
  343. =pod
  344. =item summary logical device for a digital reading from a S7/S5
  345. =item summary_DE logisches Device für einen binären Nur Lese Datenpunkt von einer S5 / S7
  346. =begin html
  347. <a name="S7_DRead"></a>
  348. <h3>S7_DRead</h3>
  349. <ul>
  350. This module is a logical module of the physical module S7. <br>
  351. This module provides digital data (ON/OFF).<br>
  352. Note: you have to configure a PLC reading at the physical modul (S7) first.<br>
  353. <br><br>
  354. <b>Define</b>
  355. <ul>
  356. <code>define &lt;name&gt; S7_DRead {inputs|outputs|flags|db} &lt;DB&gt; &lt;address&gt;</code>
  357. <ul>
  358. <li>inputs|outputs|flags|db … defines where to read.</li>
  359. <li>DB … Number of the DB</li>
  360. <li>address … address you want to read. bit number to read. Example: 10.3</li>
  361. </ul>
  362. Note: the required memory area need to be with in the configured PLC reading of the physical module.
  363. </ul>
  364. </ul>
  365. =end html
  366. =begin html_DE
  367. <a name="S7_DRead"></a>
  368. <h3>S7_DRead</h3>
  369. <ul>
  370. This module is a logical module of the physical module S7. <br>
  371. This module provides digital data (ON/OFF).<br>
  372. Note: you have to configure a PLC reading at the physical modul (S7) first.<br>
  373. <br><br>
  374. <b>Define</b>
  375. <ul>
  376. <code>define &lt;name&gt; S7_DRead {inputs|outputs|flags|db} &lt;DB&gt; &lt;address&gt;</code>
  377. <ul>
  378. <li>inputs|outputs|flags|db … defines where to read.</li>
  379. <li>DB … Number of the DB</li>
  380. <li>address … address you want to read. bit number to read. Example: 10.3</li>
  381. </ul>
  382. Note: the required memory area need to be with in the configured PLC reading of the physical module.
  383. </ul>
  384. </ul>
  385. =end html_DE
  386. =cut