16_STACKABLE.pm 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230
  1. ##############################################
  2. # $Id: 16_STACKABLE.pm 14018 2017-04-17 16:33:06Z rudolfkoenig $
  3. package main;
  4. use strict;
  5. use warnings;
  6. #####################################
  7. sub
  8. STACKABLE_Initialize($)
  9. {
  10. my ($hash) = @_;
  11. $hash->{Match} = "^\\*";
  12. $hash->{DefFn} = "STACKABLE_Define";
  13. $hash->{UndefFn} = "STACKABLE_Undef";
  14. $hash->{ParseFn} = "STACKABLE_Parse";
  15. $hash->{NotifyFn} = "STACKABLE_Notify";
  16. $hash->{AttrList} = "IODev ignore:1,0 binary:1,0 writePrefix";
  17. $hash->{noRawInform} = 1; # Our message was already sent as raw.
  18. $hash->{noAutocreatedFilelog} = 1;
  19. $hash->{IOOpenFn} = "STACKABLE_IOOpenFn";
  20. $hash->{IOReadFn} = "STACKABLE_IOReadFn";
  21. $hash->{IOWriteFn} = "STACKABLE_IOWriteFn";
  22. }
  23. #####################################
  24. sub
  25. STACKABLE_Define($$)
  26. {
  27. my ($hash, $def) = @_;
  28. my @a = split("[ \t][ \t]*", $def);
  29. return "wrong syntax: define <name> STACKABLE baseDevice"
  30. if(int(@a) != 3);
  31. my $io = $defs{$a[2]};
  32. return "$a[2] is not a valid device"
  33. if(!$io);
  34. return "$io->{NAME} already has a stacked device: $io->{STACKED}"
  35. if($io->{STACKED});
  36. $io->{STACKED} = $hash->{NAME};
  37. $hash->{IODev} = $io;
  38. delete($io->{".clientArray"}); # Force a recompute
  39. $hash->{STATE} = "Defined";
  40. notifyRegexpChanged($hash, $a[2]);
  41. return undef;
  42. }
  43. #####################################
  44. sub
  45. STACKABLE_Parse($$)
  46. {
  47. my ($iohash,$msg) = @_;
  48. return "UNDEFINED $iohash->{NAME}_STACKABLE STACKABLE $iohash->{NAME}"
  49. if(!$iohash->{STACKED});
  50. my $name = $iohash->{STACKED};
  51. return "" if(IsIgnored($name));
  52. $msg =~ s/^.//; # Cut off prefix *
  53. my $sh = $defs{$name};
  54. my $ch = $sh->{".clientHash"};
  55. if($ch) {
  56. delete $ch->{IOReadFn};
  57. $ch->{IODevRxBuffer} = (AttrVal($name,"binary",0) ?
  58. pack("H*",$msg) : $msg."\n");
  59. CallFn($ch->{NAME}, "ReadFn", $ch);
  60. $ch->{IOReadFn} = "STACKABLE_IOReadFn";
  61. } else {
  62. Log 1, "$name: no client device assigned";
  63. }
  64. return "";
  65. }
  66. sub
  67. STACKABLE_Undef($$)
  68. {
  69. my ($hash, $arg) = @_;
  70. delete $hash->{IODev}{STACKED};
  71. return undef;
  72. }
  73. sub
  74. STACKABLE_Notify($$)
  75. {
  76. my ($me, $src) = @_;
  77. my $eva = deviceEvents($src,0);
  78. return undef if(!$eva || !@$eva);
  79. my $evt = $eva->[0];
  80. my $tgt = $me->{".clientHash"};
  81. if($evt eq "DISCONNECTED") {
  82. DevIo_Disconnected($tgt);
  83. my ($dev, undef) = split("@", $tgt->{DeviceName});
  84. delete $readyfnlist{"$tgt->{NAME}.$dev"}; # no polling by child devices
  85. delete $tgt->{DevIoJustClosed};
  86. } elsif($evt eq "CONNECTED") {
  87. CallFn($tgt->{NAME}, "ReadyFn", $tgt);
  88. }
  89. return undef;
  90. }
  91. sub
  92. STACKABLE_IOOpenFn($)
  93. {
  94. my ($hash) = @_;
  95. $hash->{FD} = $hash->{IODev}{IODev}{FD}; # Lets fool the client
  96. $hash->{IODev}{".clientHash"} = $hash;
  97. $hash->{IOReadFn} = "STACKABLE_IOReadFn";
  98. return 1;
  99. }
  100. sub
  101. STACKABLE_IOReadFn($) # used by synchronuous get
  102. {
  103. my ($hash) = @_;
  104. my $me = $hash->{IODev};
  105. my $buf = "";
  106. if($me->{IODev} && $me->{IODev}{PARTIAL}) {
  107. $buf = $me->{IODev}{PARTIAL};
  108. $me->{IODev}{PARTIAL} = "";
  109. }
  110. while($buf !~ m/\n/) {
  111. my $ret = DevIo_SimpleReadWithTimeout($me->{IODev}, 1); # may block
  112. return undef if(!defined($ret));
  113. $buf .= $ret;
  114. }
  115. my $mName = $me->{NAME};
  116. Log3 $mName, 5, "$mName read: $buf";
  117. my @l = split("\n", $buf);
  118. $buf = join("\n", grep { $_ =~ m/^\*/ } @l)."\n";
  119. $buf =~ s/^\*//gsm;
  120. if(AttrVal($me->{NAME},"binary",0)) {
  121. $buf =~ s/[\r\n]//g;
  122. return pack("H*",$buf);
  123. } else {
  124. return $buf;
  125. }
  126. }
  127. sub
  128. STACKABLE_IOWriteFn($$)
  129. {
  130. my ($hash, $msg) = @_;
  131. my $myhash = $hash->{IODev};
  132. my $myname = $myhash->{NAME};
  133. my $prf = AttrVal($myname,"writePrefix","*");
  134. if(AttrVal($myname,"binary",0)) {
  135. return IOWrite($myhash, "", $prf.unpack("H*",$msg));
  136. } else {
  137. $msg =~ s/[\r\n]//g;
  138. return IOWrite($myhash, "", $prf.$msg);
  139. }
  140. }
  141. 1;
  142. =pod
  143. =item summary Module for stacked IO devices like the Busware SCC
  144. =item summary_DE Modul fuer gestapelte IO Ger&auml;te wie das Busware SCC
  145. =begin html
  146. <a name="STACKABLE"></a>
  147. <h3>STACKABLE</h3>
  148. <ul>
  149. This module is a more generic version of the STACKABLE_CC module, and is used
  150. for stacked IO devices like the Busware SCC. It works by adding/removing a
  151. prefix (default is *) to the command, and redirecting the output to the
  152. module, which is using it.
  153. <a name="STACKABLEdefine"></a>
  154. <b>Define</b>
  155. <ul>
  156. <code>define &lt;name&gt; STACKABLE &lt;baseDevice&gt;</code> <br>
  157. <br>
  158. &lt;baseDevice&gt; is the name of the unterlying device.<br>
  159. Example:
  160. <ul><code>
  161. define CUL_1 CUL /dev/ttyAMA0@38400<br>
  162. attr CUL_1 rfmode SlowRF<br><br>
  163. define CUL_1_SCC STACKABLE CUL1<br>
  164. define CUL_2 CUL FHEM:DEVIO:CUL_1_SCC:9600 0000<br>
  165. attr CUL_2 rfmode HomeMatic<br><br>
  166. define CUL_2_SCC STACKABLE CUL2<br>
  167. define CUL_3 ZWCUL FHEM:DEVIO:CUL_2_SCC:9600 12345678 01<br>
  168. </code></ul>
  169. <b>Note:</b>If you rename the base CUL or a STACKABLE, which is a base for
  170. another one, the definition of the next one has to be adjusted, and FHEM
  171. has to be restarted.
  172. </ul>
  173. <a name="STACKABLEset"></a>
  174. <b>Set</b> <ul>N/A</ul><br>
  175. <a name="STACKABLEget"></a>
  176. <b>Get</b> <ul>N/A</ul><br>
  177. <a name="STACKABLEattr"></a>
  178. <b>Attributes</b>
  179. <ul>
  180. <li><a name="#writePrefix">writePrefix</a><br>
  181. The prefix used when writing data, default is *.
  182. "readPrefix" is hardcoded to *.
  183. </li><br>
  184. <li><a name="#binary">binary</a><br>
  185. If set to true, read data is converted to binary from hex before offering
  186. it to the client IO device (e.g. TCM). Default is 0 (off).
  187. </li><br>
  188. </ul>
  189. </ul>
  190. =end html
  191. =cut