amplifierPower.pl 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  1. #!/usr/bin/perl
  2. use strict;
  3. use warnings;
  4. use IPC::System::Simple qw( system capture );
  5. use Time::HiRes qw( usleep sleep time );
  6. # Local modules
  7. use Cwd qw(abs_path);
  8. use File::Basename qw(dirname);
  9. use lib dirname(abs_path($0));
  10. use DMX;
  11. # Prototypes
  12. sub sendCmd($$);
  13. # App config
  14. my $DATA_DIR = DMX::dataDir();
  15. my $STATE_SOCK = 'AMPLIFIER_POWER';
  16. my $AMP_SOCK = 'AMPLIFIER';
  17. my $OUTPUT_FILE = $DATA_DIR . $STATE_SOCK;
  18. my $PUSH_TIMEOUT = 20;
  19. my $PULL_TIMEOUT = $PUSH_TIMEOUT * 3;
  20. my $DELAY = $PULL_TIMEOUT / 2;
  21. my $CMD_DELAY = 5.0;
  22. my $AUTO_CMD = 'INPUT_AUTO';
  23. # Debug
  24. my $DEBUG = 0;
  25. if ($ENV{'DEBUG'}) {
  26. $DEBUG = 1;
  27. }
  28. # Sockets
  29. DMX::stateSocket($STATE_SOCK);
  30. DMX::stateSubscribe($STATE_SOCK);
  31. my $amp = DMX::clientSock($AMP_SOCK);
  32. # State
  33. my $state = 'OFF';
  34. my $mode = 'SURROUND';
  35. my $input = 'TV';
  36. my $stateLast = $state;
  37. my %exists = ();
  38. my $pushLast = 0;
  39. my $pullLast = time();
  40. my $update = 0;
  41. my $lastMode = 0;
  42. my $lastInput = 0;
  43. my $lastPower = 0;
  44. # Loop forever
  45. while (1) {
  46. # State is calculated; use newState to gather data
  47. my $newState = $state;
  48. # Avoid repeated calls to time()
  49. my $now = time();
  50. # Wait for state updates
  51. my $cmdState = DMX::readState($DELAY, \%exists, undef(), undef());
  52. if (defined($cmdState)) {
  53. $newState = $cmdState;
  54. $pullLast = $now;
  55. }
  56. # Die if we don't see regular updates
  57. if ($now - $pullLast > $PULL_TIMEOUT) {
  58. die('No update on state socket in past ' . $PULL_TIMEOUT . " seconds. Exiting...\n");
  59. }
  60. # Calculate the new state
  61. $stateLast = $state;
  62. if ($newState eq 'PLAY') {
  63. $state = 'ON';
  64. } elsif ($exists{'RAVE'}) {
  65. $state = 'RAVE';
  66. } elsif ($newState eq 'PAUSE') {
  67. $state = 'ON';
  68. } else {
  69. $state = 'OFF';
  70. }
  71. # Calculate the channel mode
  72. if ($exists{'STEREO_CMD'} || $exists{'PLAYING_TYPE'} eq 'audio' || $state eq 'RAVE') {
  73. $mode = 'STEREO';
  74. } else {
  75. $mode = 'SURROUND';
  76. }
  77. # Force updates on a periodic basis
  78. if (!$update && $now - $pushLast > $PUSH_TIMEOUT) {
  79. # Not for the amp
  80. #if ($DEBUG) {
  81. # print STDERR "Forcing periodic update\n";
  82. #}
  83. #$update = 1;
  84. }
  85. # Force updates on any state change
  86. if (!$update && $stateLast ne $state) {
  87. if ($DEBUG) {
  88. print STDERR 'State change: ' . $stateLast . ' => ' . $state . "\n";
  89. }
  90. $update = 1;
  91. }
  92. # Force updates when there is a physical state mistmatch
  93. if (!$update && (($state eq 'OFF' && $exists{'AMPLIFIER'}) || ($state eq 'ON' && !$exists{'AMPLIFIER'}))) {
  94. if ($DEBUG) {
  95. print STDERR 'Physical state mismatch: ' . $state . ':' . $exists{'AMPLIFIER'} . "\n";
  96. }
  97. $update = 1;
  98. }
  99. # Set the channel mode as needed
  100. if ($exists{'AMPLIFIER'} && $exists{'AMPLIFIER_MODE'} ne $mode && $lastMode < $now - $CMD_DELAY) {
  101. $lastMode = $now;
  102. if ($DEBUG) {
  103. print STDERR 'Setting mode to: ' . $mode . "\n";
  104. }
  105. DMX::say('Amplifier mode: ' . $mode);
  106. sendCmd($amp, $mode);
  107. # Reset the input mode anytime we switch to SURROUND
  108. if ($mode eq 'SURROUND') {
  109. sendCmd($amp, $AUTO_CMD);
  110. }
  111. }
  112. # Set the amplifier input as needed
  113. if ($exists{'AMPLIFIER'} && $exists{'AMPLIFIER_INPUT'} ne $input && $lastInput < $now - $CMD_DELAY) {
  114. $lastInput = $now;
  115. if ($DEBUG) {
  116. print STDERR 'Setting input to: ' . $input . "\n";
  117. }
  118. DMX::say('Amplifier input: ' . $input);
  119. sendCmd($amp, $input);
  120. }
  121. # Update the amp
  122. if ($update) {
  123. # Extra debugging to record pushes
  124. if ($DEBUG) {
  125. print STDERR 'State: ' . $state . "\n";
  126. }
  127. # Send master power state
  128. my $cmd = undef();
  129. if ($state eq 'OFF' || $state eq 'ON') {
  130. $cmd = $state;
  131. } elsif ($state eq 'RAVE') {
  132. $cmd = 'ON';
  133. }
  134. if (defined($cmd) && $lastPower < $now - $CMD_DELAY) {
  135. $lastPower = $now;
  136. sendCmd($amp, $cmd);
  137. }
  138. # No output file
  139. # Update the push time
  140. $pushLast = $now;
  141. # Clear the update flag
  142. $update = 0;
  143. }
  144. }
  145. # Send the requested command and enforce an inter-command delay
  146. sub sendCmd($$) {
  147. my ($amp, $cmd) = @_;
  148. # Send the command
  149. $amp->send($cmd)
  150. or die('Unable to write command to amp socket: ' . $cmd . ": ${!}\n");
  151. # A tiny delay to keep the serial port stable in repeated calls
  152. sleep(0.1);
  153. }