Deactivate +5v signal when there is not input signal
This commit is contained in:
1 parent
a734b5f780
commit
6d2fd26f66
1 file changed
+68
-65
+68
-65
@@ -15,9 +15,10 @@ class Vertex2(SmartObject):
|
||||
self._stop_interrupt_listener()
|
||||
self._interrupt_stop = threading.Event()
|
||||
self._status_requested = threading.Event()
|
||||
self._tx0_recovery_attempted = False
|
||||
self._tx0_recovery_restore_handle = None
|
||||
|
||||
self._plus5_off_handle = None
|
||||
self._plus5_active_index = None
|
||||
self._input_signal_present = False
|
||||
self.plus5_signal_timeout = max(0, float(self.args.get('plus5_signal_timeout', 60)))
|
||||
self.video_tx_signal_sensor = self.create_entity(
|
||||
self.args['video_tx_signal_sensor'],
|
||||
state='unavailable',
|
||||
@@ -175,21 +176,12 @@ class Vertex2(SmartObject):
|
||||
buffer = ''
|
||||
status = {}
|
||||
status_started = None
|
||||
interrupt_generation = 0
|
||||
last_interrupt_at = None
|
||||
last_interrupt_interval = None
|
||||
request_generation = 0
|
||||
request_interval = None
|
||||
previous_snapshot = None
|
||||
previous_snapshot_generation = None
|
||||
|
||||
while not interrupt_stop.is_set():
|
||||
if status_started is None and self._status_requested.is_set():
|
||||
self._status_requested.clear()
|
||||
status = {}
|
||||
status_started = time.monotonic()
|
||||
request_generation = interrupt_generation
|
||||
request_interval = last_interrupt_interval
|
||||
for command in commands:
|
||||
connection.sendall((command + '\r').encode('ascii'))
|
||||
|
||||
@@ -214,10 +206,6 @@ class Vertex2(SmartObject):
|
||||
line = line.strip()
|
||||
if line == 'int':
|
||||
self.log_info('Vertex2 IP INTERRUPT received')
|
||||
now = time.monotonic()
|
||||
last_interrupt_interval = None if last_interrupt_at is None else now - last_interrupt_at
|
||||
last_interrupt_at = now
|
||||
interrupt_generation += 1
|
||||
self._status_requested.set()
|
||||
elif status_started is not None:
|
||||
if line.startswith('insel '):
|
||||
@@ -236,23 +224,6 @@ class Vertex2(SmartObject):
|
||||
tx0=snapshot['tx0'], tx1=snapshot['tx1'],
|
||||
audout=snapshot['audout'], insel=snapshot['insel'])
|
||||
status_started = None
|
||||
consecutive = (previous_snapshot_generation is not None
|
||||
and request_generation == previous_snapshot_generation + 1)
|
||||
unchanged = previous_snapshot == snapshot
|
||||
rx_has_signal = any(
|
||||
snapshot[field].strip().lower() not in ('', 'no signal', 'unavailable')
|
||||
for field in ('rx0', 'rx1')
|
||||
)
|
||||
if (unchanged and consecutive and request_interval is not None
|
||||
and 2 <= request_interval < 3 and not rx_has_signal):
|
||||
if not self._tx0_recovery_attempted:
|
||||
self.run_in(self.trigger_tx0_stuck_workaround, 0,
|
||||
interrupt_interval=request_interval,
|
||||
snapshot=snapshot)
|
||||
elif not unchanged:
|
||||
self._tx0_recovery_attempted = False
|
||||
previous_snapshot = snapshot
|
||||
previous_snapshot_generation = request_generation
|
||||
|
||||
if status_started is not None and time.monotonic() - status_started > 5:
|
||||
raise OSError('Vertex2 TCP status response timed out')
|
||||
@@ -271,30 +242,6 @@ class Vertex2(SmartObject):
|
||||
self.log_warning(f'Vertex2 IP INTERRUPT unavailable: {error}')
|
||||
interrupt_stop.wait(5)
|
||||
|
||||
def trigger_tx0_stuck_workaround(self, kwargs):
|
||||
if self._tx0_recovery_attempted:
|
||||
return
|
||||
if self.output_selected_sensor.get_state() != self.get_output_config(0)['name']:
|
||||
return
|
||||
if self.unreachable_sensor.get_state() != 'off':
|
||||
return
|
||||
|
||||
self._tx0_recovery_attempted = True
|
||||
snapshot_summary = ', '.join(f'{key}={value!r}' for key, value in kwargs['snapshot'].items())
|
||||
self.log_warning(
|
||||
f"Vertex2 TX0 +5V workaround triggered: identical complete TCP status after "
|
||||
f"an IP INTERRUPT interval of {kwargs['interrupt_interval']:.2f}s "
|
||||
f"({snapshot_summary}); cycling TX0 +5V FORCE"
|
||||
)
|
||||
self.force_tx0_plus5(False)
|
||||
self._tx0_recovery_restore_handle = self.run_in(self.restore_tx0_plus5_after_recovery, 1)
|
||||
|
||||
def restore_tx0_plus5_after_recovery(self, kwargs):
|
||||
self._tx0_recovery_restore_handle = None
|
||||
if self.output_selected_sensor.get_state() == self.get_output_config(0)['name']:
|
||||
self.log_info('Vertex2 TX0 +5V workaround: restoring TX0 +5V FORCE')
|
||||
self.force_tx0_plus5(True)
|
||||
|
||||
def _stop_interrupt_listener(self):
|
||||
interrupt_stop = getattr(self, '_interrupt_stop', None)
|
||||
if interrupt_stop is not None:
|
||||
@@ -306,13 +253,15 @@ class Vertex2(SmartObject):
|
||||
if interrupt_thread.is_alive():
|
||||
raise RuntimeError('Previous Vertex2 IP INTERRUPT listener did not stop')
|
||||
self._interrupt_thread = None
|
||||
restore_handle = getattr(self, '_tx0_recovery_restore_handle', None)
|
||||
if restore_handle is not None:
|
||||
self.cancel_timer(restore_handle)
|
||||
self._tx0_recovery_restore_handle = None
|
||||
plus5_off_handle = getattr(self, '_plus5_off_handle', None)
|
||||
if plus5_off_handle is not None:
|
||||
self.cancel_timer(plus5_off_handle)
|
||||
self._plus5_off_handle = None
|
||||
|
||||
def terminate(self):
|
||||
self._stop_interrupt_listener()
|
||||
if getattr(self, '_plus5_active_index', None) is not None:
|
||||
self._set_active_output_plus5(None)
|
||||
super().terminate()
|
||||
|
||||
def generate_input_selected_sensor_name(self,i):
|
||||
@@ -394,13 +343,10 @@ class Vertex2(SmartObject):
|
||||
self.log_info(f"Selecting TX{output_index} as the active output")
|
||||
self.apply_output_audio_settings(output_index)
|
||||
if output_index == 0:
|
||||
self.force_tx1_plus5(False)
|
||||
self.set_edid_video_flags_to_tx0()
|
||||
self.force_tx0_plus5(True)
|
||||
else:
|
||||
self.force_tx0_plus5(False)
|
||||
self.set_edid_video_flags_to_tx1()
|
||||
self.force_tx1_plus5(True)
|
||||
self._set_active_output_plus5(output_index if self._input_signal_present else None)
|
||||
|
||||
def disable_output_selection(self):
|
||||
default_output_config = self.get_output_config(None)
|
||||
@@ -409,9 +355,61 @@ class Vertex2(SmartObject):
|
||||
attributes={"icon": default_output_config["icon"]},
|
||||
)
|
||||
self._refresh_selected_output_signal()
|
||||
self._set_active_output_plus5(None)
|
||||
|
||||
def _set_active_output_plus5(self, output_index):
|
||||
if self._plus5_off_handle is not None:
|
||||
self.cancel_timer(self._plus5_off_handle)
|
||||
self._plus5_off_handle = None
|
||||
|
||||
previous_index = self._plus5_active_index
|
||||
if previous_index == output_index:
|
||||
return
|
||||
|
||||
if previous_index == 0:
|
||||
self.force_tx0_plus5(False)
|
||||
elif previous_index == 1:
|
||||
self.force_tx1_plus5(False)
|
||||
|
||||
self._plus5_active_index = output_index
|
||||
if output_index == 0:
|
||||
# At startup the previous hardware state is unknown; disable the
|
||||
# other output only after a signal confirms the selected TX.
|
||||
self.force_tx1_plus5(False)
|
||||
self.force_tx0_plus5(True)
|
||||
elif output_index == 1:
|
||||
self.force_tx0_plus5(False)
|
||||
self.force_tx1_plus5(True)
|
||||
|
||||
def _update_plus5_from_input_signal(self, has_signal):
|
||||
self._input_signal_present = has_signal
|
||||
selected_name = self.output_selected_sensor.get_state()
|
||||
selected_index = self.output_names.get(selected_name)
|
||||
|
||||
if has_signal:
|
||||
self._set_active_output_plus5(selected_index)
|
||||
elif selected_index in (0, 1) and self._plus5_off_handle is None:
|
||||
self.log_info(
|
||||
f"No input signal; turning selected TX +5V FORCE off in {self.plus5_signal_timeout:g}s"
|
||||
)
|
||||
self._plus5_off_handle = self.run_in(
|
||||
self._turn_off_plus5_after_signal_loss,
|
||||
self.plus5_signal_timeout,
|
||||
)
|
||||
|
||||
def _turn_off_plus5_after_signal_loss(self, kwargs):
|
||||
self._plus5_off_handle = None
|
||||
if self._input_signal_present:
|
||||
return
|
||||
self.log_info("Input signal absent for configured timeout; turning selected TX +5V FORCE off")
|
||||
selected_index = self.output_names.get(self.output_selected_sensor.get_state())
|
||||
if selected_index == 0:
|
||||
self.force_tx0_plus5(False)
|
||||
elif selected_index == 1:
|
||||
self.force_tx1_plus5(False)
|
||||
if self._plus5_active_index == selected_index:
|
||||
self._plus5_active_index = None
|
||||
|
||||
def on_filmmaker_mode_conditions_change(self,prev_result,result):
|
||||
if result == SmartCondition.Result.Succeeded:
|
||||
self.toggle_filmmaker_mode(True)
|
||||
@@ -646,6 +644,11 @@ class Vertex2(SmartObject):
|
||||
selected_output_index = self.output_names.get(self.output_selected_sensor.get_state())
|
||||
self._refresh_selected_input_sensor(selected_output_index)
|
||||
self._update_output_video_sensors(kwargs['rx0'], kwargs['rx1'])
|
||||
has_input_signal = any(
|
||||
signal.strip().lower() not in ('', 'no signal', 'unavailable')
|
||||
for signal in (kwargs['rx0'], kwargs['rx1'])
|
||||
)
|
||||
self._update_plus5_from_input_signal(has_input_signal)
|
||||
if self.audio_out_signal_sensor.get_state() != audio_out_signal:
|
||||
self.audio_out_signal_sensor.set_state(state=audio_out_signal)
|
||||
self.unreachable_sensor.set_state(state='off')
|
||||
Reference in new issue
Block a user