PageRenderTime 54ms CodeModel.GetById 24ms RepoModel.GetById 0ms app.codeStats 0ms

/tags/v2-103/lib/Serial_Item.pm

#
Perl | 311 lines | 264 code | 27 blank | 20 comment | 39 complexity | d3e04bca969400dd1b05e077bf893849 MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.0, GPL-3.0
  1. # $Date: 2006-09-26 03:39:02 +0200 (Tue, 26 Sep 2006) $
  2. # $Revision: 910 $
  3. use strict;
  4. package Serial_Item;
  5. use X10_Interface;
  6. our $mainHash=\%::Serial_Ports;
  7. @Serial_Item::ISA = ('X10_Interface');
  8. our @supported_interfaces=qw!cm11 BX24 Homevision HomeBase Stargate HouseLinc
  9. Marrick cm17 Lynx10PLC weeder wish iplcs!;
  10. sub new {
  11. my ($class, $id, $state, $device_name) = @_;
  12. my $self = X10_Interface->new($id, $state, $device_name);
  13. bless ($self, $class);
  14. $self->{mainHash}=$mainHash;
  15. $self->set_standard_config;
  16. $self->set_interface($device_name) if $id and $id =~ /^X/;
  17. $self->state_overload('off'); # By default, do not process ~;: strings as substate/multistate
  18. return $self;
  19. }
  20. sub do_start {
  21. my ($self) = @_;
  22. return &::serial_port_open($self->{device_name});
  23. }
  24. sub stop {
  25. my ($self) = @_;
  26. my $port_name = $self->{port_name};
  27. my $sp_object = $main::Serial_Ports{$port_name}{object};
  28. if ($sp_object) {
  29. my $port = $main::Serial_Ports{$port_name}{port};
  30. # &Win32::SerialPort::debug(1);
  31. if ($sp_object->close) {
  32. print "Port $port_name on port $port was closed\n";
  33. }
  34. else {
  35. print "Serial_Item stop failed for port $port_name\n";
  36. }
  37. # Delete the ports, even if it didn't close, so we can do
  38. # starts again without a 'port reuse' message.
  39. delete $main::Serial_Ports{$port_name}{object};
  40. delete $main::Serial_Ports{object_by_port}{$port};
  41. # &Win32::SerialPort::debug(0);
  42. }
  43. else {
  44. print "Error in Serial_Item stop for port $port_name: Port is not started\n";
  45. }
  46. }
  47. sub set_dtr {
  48. my ($self, $state) = @_;
  49. my $port_name = $self->{port_name};
  50. if (my $serial_port = $main::Serial_Ports{$port_name}{object}) {
  51. $main::Serial_Ports{$port_name}{object}->dtr_active($state);
  52. print "Serial_port $port_name dtr set to $state\n" if $main::Debug{serial};
  53. }
  54. else {
  55. print "Error, serial port set_dtr for $port_name failed, port has not been set\n";
  56. }
  57. }
  58. sub set_rts {
  59. my ($self, $state) = @_;
  60. my $port_name = $self->{port_name};
  61. if (my $serial_port = $main::Serial_Ports{$port_name}{object}) {
  62. $main::Serial_Ports{$port_name}{object}->rts_active($state);
  63. print "Serial_port $port_name rts set to $state\n" if $main::Debug{serial};
  64. }
  65. else {
  66. print "Error, serial port set_rts for $port_name failed, port has not been set\n";
  67. }
  68. }
  69. sub write_data {
  70. my ($self, $serial_data) = @_;
  71. &send_serial_data($self->{device_name}, $serial_data);
  72. }
  73. sub send_serial_data {
  74. my ($port_name, $serial_data)=@_;
  75. return if &main::proxy_send($port_name, 'send_serial_data', $serial_data);
  76. # The ncpuxa code works on a socket, not a serial port
  77. # but may be called as a Serial_Item
  78. unless ($main::Serial_Ports{$port_name}{object} or lc $port_name eq 'ncpuxa') {
  79. print "Error, serial port for $port_name has not been set: data=$serial_data\n";
  80. return;
  81. }
  82. if (lc $port_name eq 'homevision') {
  83. print "Using homevision to send: $serial_data\n";
  84. &Homevision::send($main::Serial_Ports{Homevision}{object}, $serial_data);
  85. }
  86. elsif (lc $port_name eq 'ncpuxa') {
  87. &main::print_log("Using ncpuxa to send: $serial_data");
  88. &ncpuxa_mh::send($main::config_parms{ncpuxa_port}, $serial_data);
  89. }
  90. else {
  91. my $datatype = $main::Serial_Ports{$port_name}{datatype};
  92. my $prefix = $main::Serial_Ports{$port_name}{prefix};
  93. $serial_data = $prefix . $serial_data if $prefix and $prefix ne '';
  94. $serial_data .= "\r" unless $datatype and $datatype eq 'raw';
  95. my $results = $main::Serial_Ports{$port_name}{object}->write($serial_data);
  96. # &main::print_log("serial port=$port_name out=$serial_data results=$results") if $main::Debug{serial};
  97. print "serial port=$port_name out=$serial_data results=$results\n" if $main::Debug{serial};
  98. }
  99. }
  100. my $x10_save_unit;
  101. sub send_x10_data {
  102. # This function can either be called as a class method or a library function
  103. # If being called as a member function, then pull the object ref off the
  104. # argument list.
  105. my $self=undef;
  106. if (ref($_[0])) {
  107. $self=shift @_;
  108. }
  109. my ($interface, $serial_data, $module_type) = @_;
  110. my ($isfunc);
  111. # Use proxy mh if present (avoids mh pauses for slow X10 xmits)
  112. return if &main::proxy_send($interface, 'send_x10_data', $serial_data, $module_type);
  113. # This function can either be called as a class method or a library function
  114. if ($serial_data =~ /^X[A-P][1-9A-G]$/) {
  115. $isfunc = 0;
  116. $x10_save_unit = $serial_data;
  117. }
  118. else {
  119. $isfunc = 1;
  120. }
  121. print "X10: interface=$interface isfunc=$isfunc save_unit=$x10_save_unit data=$serial_data\n" if $main::Debug{x10};
  122. if ($interface eq 'cm11') {
  123. # CM11 wants individual codes without X
  124. print "db1 CM11: Sending x10 data: $serial_data\n" if $main::Debug{cm11};
  125. # Standard 1-cm11 code
  126. if (!$main::config_parms{cm11_bak_port}) {
  127. &ControlX10::CM11::send($main::Serial_Ports{cm11}{object},
  128. substr($serial_data, 1));
  129. }
  130. # Dual cm11 code
  131. else {
  132. # if both units are active then
  133. # use the one with the most time left on the counter as it was the most recently found to be active
  134. # otherwise use the main one if it's active or the backup if it's active
  135. if (($main::cm11_objects{active}->state() eq 'on') && ($main::cm11_objects{bak_active}->state() eq 'on')) {
  136. if ($main::cm11_objects{timer}->seconds_remaining() >= $main::cm11_objects{bak_timer}->seconds_remaining()) {
  137. print "db CM11: using primary cm11\n" if $main::Debug{cm11};
  138. &ControlX10::CM11::send($main::Serial_Ports{cm11}{object},substr($serial_data, 1));
  139. } else {
  140. print "db CM11: using backup cm11\n" if $main::Debug{cm11};
  141. &ControlX10::CM11::send($main::Serial_Ports{cm11_bak}{object},substr($serial_data, 1));
  142. }
  143. } elsif ($main::cm11_objects{active}->state() eq 'on') {
  144. print "db CM11: using primary cm11\n" if $main::Debug{cm11};
  145. &ControlX10::CM11::send($main::Serial_Ports{cm11}{object},substr($serial_data, 1));
  146. } elsif ($main::cm11_objects{bak_active}->state() eq 'on') {
  147. print "db CM11: using backup cm11\n" if $main::Debug{cm11};
  148. &ControlX10::CM11::send($main::Serial_Ports{cm11_bak}{object},substr($serial_data, 1));
  149. } else {
  150. print "db CM11: Error - no cm11's are working ...\n" if $main::Debug{cm11};
  151. }
  152. }
  153. }
  154. elsif ($interface eq 'ti103') {
  155. # TI103 wants individual codes without X
  156. print "db1 TI103: Sending x10 data: $serial_data\n" if $main::Debug{ti103};
  157. &ControlX10::TI103::send($main::Serial_Ports{ti103}{object}, substr($serial_data, 1));
  158. }
  159. elsif ($interface eq 'bx24') {
  160. # BX24 wants individual codes without X
  161. &X10_BX24::SendX10($serial_data);
  162. }
  163. elsif ($interface eq 'lynx10plc') {
  164. # marrick PLC wants XA1AK
  165. &Lynx10PLC::send_plc($main::Serial_Ports{Lynx10PLC}{object},
  166. $serial_data, $module_type);
  167. }
  168. elsif ($interface eq 'cm17') {
  169. # cm17 wants A1K, not XA1AK
  170. &ControlX10::CM17::send($main::Serial_Ports{cm17}{object},
  171. substr($x10_save_unit, 1) . substr($serial_data, 2)) if $isfunc;
  172. }
  173. elsif ($interface eq 'homevision') {
  174. # homevision wants XA1AK
  175. if ($isfunc) {
  176. print "Using homevision to send: " .
  177. $x10_save_unit . substr($serial_data, 1) . "\n";
  178. &Homevision::send($main::Serial_Ports{Homevision}{object},
  179. $x10_save_unit . substr($serial_data, 1));
  180. }
  181. }
  182. elsif ($interface eq 'homebase') {
  183. # homebase wants individual codes without X
  184. print "Using homebase to send: $serial_data\n";
  185. &HomeBase::send_X10($main::Serial_Ports{HomeBase}{object}, substr($serial_data, 1));
  186. }
  187. elsif ($interface eq 'stargate') {
  188. # Stargate wants individual codes without X
  189. print "Using stargate to send: $serial_data\n";
  190. &Stargate::send_X10($main::Serial_Ports{Stargate}{object}, substr($serial_data, 1));
  191. }
  192. elsif ($interface eq 'houselinc') {
  193. # houselinc wants XA1AK
  194. if ($isfunc) {
  195. print "Using houselinc to send: " .
  196. $x10_save_unit . substr($serial_data, 1) . "\n";
  197. &HouseLinc::send_X10($main::Serial_Ports{HouseLinc}{object},
  198. $x10_save_unit . substr($serial_data, 1));
  199. }
  200. }
  201. elsif ($interface eq 'marrick') {
  202. # marrick wants XA1AK
  203. if ($isfunc) {
  204. print "Using marrick to send: " .
  205. $x10_save_unit . substr($serial_data, 1) . "\n";
  206. &Marrick::send_X10($main::Serial_Ports{Marrick}{object},
  207. $x10_save_unit . substr($serial_data, 1));
  208. }
  209. }
  210. elsif ($interface eq 'ncpuxa') {
  211. # ncpuxa wants individual codes with X
  212. &main::print_log("Using ncpuxa to send: $serial_data");
  213. &ncpuxa_mh::send($main::config_parms{ncpuxa_port}, $serial_data);
  214. }
  215. elsif ($interface eq 'weeder') {
  216. # Weeder wants XA1AK or XA1ALALAL
  217. my ($device, $house, $command) = $serial_data =~ /^X(\S\S)(\S)(\S+)/;
  218. # Allow for +-xx%
  219. my $dim_amount = 3;
  220. if ($command =~ /[\+\-]\d+/) {
  221. $dim_amount = int(10 * abs($command) / 100); # about 10 levels to 100%
  222. $command = ($command > 0) ? 'L' : 'M';
  223. }
  224. # Weeder table does not match what we defined in CM11,CM17,X10_Items.pm
  225. # - Dim -> L, Bright -> M, AllOn -> I, AllOff -> H
  226. if ($command eq 'M') {
  227. $command = 'L' . (($house . 'L') x $dim_amount);
  228. }
  229. elsif ($command eq 'L') {
  230. $command = 'M' . (($house . 'M') x $dim_amount);
  231. }
  232. elsif ($command eq 'O') {
  233. $command = 'I';
  234. }
  235. elsif ($command eq 'P') {
  236. $command = 'H';
  237. }
  238. $serial_data = 'X' . $device . $house . $command;
  239. $main::Serial_Ports{weeder}{object}->write($serial_data);
  240. # Give weeder a chance to do the previous command
  241. # Surely there must be a better way!
  242. select undef, undef, undef, 1.2;
  243. }
  244. elsif ($interface eq 'wish') {
  245. # wish wants individual codes without X
  246. &main::print_log("Using wish to send: $serial_data");
  247. &X10_Wish::send(substr($serial_data, 1));
  248. }
  249. elsif ($interface eq 'iplcs') {
  250. # ncpuxa wants individual codes with X
  251. &main::print_log("Using iplcs to send: $serial_data");
  252. &iplcs::send($main::Serial_Ports{iplcs}{object}, $serial_data);
  253. }
  254. elsif ($interface eq 'iplcu') {
  255. # ncpuxa wants individual codes with X
  256. &main::print_log("Using iplcu to send: $serial_data");
  257. &iplcs::send($main::config_parms{iplcu_port}, $serial_data);
  258. }
  259. else {
  260. print "\nError, X10 interface not found: interface=$interface, data=$serial_data\n";
  261. }
  262. }
  263. sub get_supported_interfaces {
  264. my ($self)=@_;
  265. return \@supported_interfaces;
  266. }
  267. sub serial_items_by_id {
  268. return &Device_Item::items_by_id(@_);
  269. }
  270. sub serial_item_by_id {
  271. return &Device_Item::item_by_id(@_);
  272. }
  273. 1;